문제 짧아서 아싸링 했는데 무슨 뜻인지 몰라서 넘어갔음ㅋㅋㅋㅋ
번역도 해보려 했는데 아니 이게 무슨 말이지?? 싶었다. c가 포함된 길이의 최솟값 <- 여기서 c ?? 아무 문자나 다 되는건가?? 엥?? 음?? 엄?? 최소 문자열의 길이가 k인데 k의 최솟값을 찾으라고? (멘붕중)
그래서 예시 보면서 힌트를 얻으려고 했었다. 뭔가 abacaba -> 2 이고 zzzzz -> 1 이므로 아 그럼 가장 가까운 문자의 길이를 구하는 거구나!싶었는데 abcde가 3인 거 보고 어.. 버버.. 버.. 패스했다. 계속 왜 5가 아니지 싶었음
이거 다시보니깐 그문제였다. 파라메트릭 서치!!! 반가웠음. 사실 정말 반가운 건 아니고 그냥 아는 거 나와서 조건반사적 반가움이었다. 파라메트릭 서치랑은 아직 낯선 사이임,,
이렇게 생각했는데 자꾸 어디서 문제가 생겨서 확인해봤더니 이 부분이 문제였다.
이거 a.size()여야 하는데 s.length()로 해서 z 넣으니 값이 이상하더라
#include <iostream>
#include <string>
#include <vector>
using namespace std;
bool isOk(string s, int mid){
vector<int> a(26, 0);
int i;
for(i = 0; i <= s.length() - mid ; i++){
for(int j = i; j < i+mid; j++){
if(a[s[j]-'a'] == i)
a[s[j]-'a'] = i+1;
}
}
for(int j=0; j<a.size(); j++){
if(a[j] == i)
return true;
}
return false;
}
int main() {
string s;
cin >> s;
int lo = 1;
int hi = s.length();
//이거 다시 확인해야함
int ans;
while(lo <= hi){
int mid = (lo + hi) / 2;
if(isOk(s, mid)){
hi = mid - 1;
ans = mid;
}
else{
lo = mid + 1;
}
}
printf("%d", ans);
}
완성~~
하지만 시간초과~~
길이봐 장난해요 코드포스?
(하지만 문제에 문자열 길이 10만이라 알려줬다구)
아ㅋㅋㅋㅋ
근데 왜 틀린줄 알겠다.
이분탐색을 쓰면 뭐해 함수에서 n^2을 쓰는데ㅋㅋㅋㅋ
ㅋㅋ
ㅋㅋㅋ
으악! 다시 고쳐야겠다!
아 N^2이 만까지 가능한데 내 코드는 (logN) * (N^2)이라 백퍼 터지는구나
아니 그런데 이거 제한이 2초인데???
아 그럼 N^2이 2만까지 가능한건가? 그래도 터지겠네
그다음 생각해본 게 이거..
먼저 첫 덩어리에 있는 알파벳을 다 세어준다. 알파벳이 있다면 1로
다음으로 다른 덩어리들을 확인하는데 그 덩어리에 a부터 z까지 있는지 확인한다. 해당 알파벳이 없다면 a배열의 해당 인덱스를 0으로 만들어준다.
이 반복문 돌면 덩어리 속에 계속 남아있는 알파벳은 그대로 1일꺼고 한 번이라도 없으면 0일 것이다.
남아있는 알파벳이 없으면 a배열이 전부 0이므로 그때는 check와 같아진다. -> false 반환
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
bool isOk(string s, int mid){
vector<int> a(26, 0);
vector<int> check(26, 0);
printf("%d", mid);
for(int i = 0; i < mid; i++){
a[s[i]-'a'] = 1;
}
for(int i = 1; i <= s.length() - mid ; i++){
for(int j = 'a'; j <= 'z'; j++){
char c = *lower_bound(s.begin()+i, s.begin()+mid+i-1, j);
if(c != j)
a[j-'a'] = 0;
}
}
printf("\n");
if(check == a){
printf("false");
return false;
}
printf("true");
return true;
}
int main() {
string s;
cin >> s;
int lo = 1;
int hi = s.length();
//이거 다시 확인해야함
int ans = -999;
while(lo <= hi){
int mid = (lo + hi) / 2;
if(isOk(s, mid)){
hi = mid - 1;
ans = mid;
}
else{
lo = mid + 1;
}
printf("\n\n");
}
printf("%d", ans);
}
이렇게 짰는데.. 맞는 거 같은데.. 예제 하나가 맞지 않다.
4일때 true여야 하는데 false가 떴다. 다른 예제는 맞게 나온다..
이대로 돌아가면 처음 이분탐색 logN, 함수 안에서 반복문*이분탐색 = N*log^2N 정도니 시간초과도 안 걸릴 것 같은데.. 어디서 틀렸지
오늘 D, E 다 풀려 했는데 결국 D 못 해결했음.. 좀 더 생각하면 답 알 수 있을 것 같은데 이제 지침ㅠ 내일 다시 봐야지
위의 문제 틀린 이유가 lower_bound는 정렬된 배열에서만 값을 찾아준다. 만약 정렬되지 않았다면 어떤 값을 반환할지 알 수 없다ㅋㅋㅋ 정렬 안 해줘도 찾아주는 줄 알았음 (머쓱,,) 그래서 그냥 find 함수로 찾아버릴까 했는데 얘를 쓰면 다시 시간복잡도가 n 제곱이 되어버림ㅎㅎ..ㅎㅎ
다음 방법! 너무 신기한 걸 알았다.
맨 처음 부분 배열에 있는 문자 개수를 알면 다음 부분 배열에 있는 문자 개수는 O(1)에 구할 수 있다. (아니 어떢게?)
저 규칙을 보면 중간 하늘색 부분은 똑같고 앞의 배열(i-1번째)이 없어지고 뒤의 배열(i+mid-1 번째)가 추가된다. 이 두개만 알면 다음 배열에 있는 문자 개수를 알 수 있다. 시간복잡도가 O(1) !!! 와 정말 신기하다.
이걸 이용해서 isOk() 함수를 구현했다.
처음에 배열 두개를 만들어서 하나는 문자 개수를 세고 다른 하나는 해당 문자가 계속 있는지 체크한다. 다음으로 첫 덩어리를 읽어서 문자 개수를 센다. 그리고 나타난 문자는 check 배열에 1로 만들어준다. 다음으로 덩어리를 이동시키면서 개수를 더하고 빼는데 이 때 개수가 한 번이라도 0이 되면 check 배열의 값을 0으로 만들어준다.
마지막으로 모든 과정이 다 끝나면 check 배열을 확인한다. check 배열에 1이 있으면 그 문자는 계속 나타난 것이므로 true를 반환한다. 만약 check 배열에 1이 없으면, 즉 전부 0이라면 그때는 false를 반환한다.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
bool isOk(string s, int mid){
vector<int> v(26, 0);
vector<int> check(26, 0);
vector<int> zero(26, 0);
for(int i = 0; i < mid; i++){
v[s[i]-'a']++;
check[s[i]-'a'] = 1;
}
for(int i = 1; i <= s.length() - mid ; i++){
v[s[i-1]-'a']--;
v[s[i+mid-1]-'a']++;
if(v[s[i-1]-'a'] <= 0)
check[s[i-1]-'a'] = 0;
}
if(zero == check)
return false;
return true;
}
int main() {
string s;
cin >> s;
int lo = 1;
int hi = s.length();
//이거 다시 확인해야함
int ans = -999;
while(lo <= hi){
int mid = (lo + hi) / 2;
if(isOk(s, mid)){
hi = mid - 1;
ans = mid;
}
else
lo = mid + 1;
}
printf("%d", ans);
}
코드는 위와 같다.
맞았다ㅎㅎ
이제 E번 풀러 가야지
'코드포스' 카테고리의 다른 글
[코드포스 Practice6] 후기 (0) | 2019.12.03 |
---|---|
[코드포스 Practice5] E. Joty and Chocolate (0) | 2019.11.29 |
[코드포스 Practice5] C. Mind the Gap (0) | 2019.11.27 |
[코드포스 Practice5] B. Oath of the Night's Watch (0) | 2019.11.27 |
[코드포스 Practice5] A. Splitting into digits (0) | 2019.11.27 |