본문 바로가기

코딩/알고리즘

백준 4354 문자열 제곱


KMP알고리즘을 수행하면 계산되는 pi배열 ( 다른말로 실패함수)를 이용한다.


다음과 같은 표를 살펴보자

(len은 문자열의 길이를 의미)

 문자열

 pi[len] 

 abab

 ababab

 abcabc

 aaaa

 asd


pi[len]은 문자열의 접두사 = 접미사인 index +1을 가리킨다.

즉, pi[len]은 반복되는 문자열의 길이가 반복될 수 있는 최대 길이를 의미한다.

이 말은 다른 말로, len - pi[len]이 문자열에서 반복되는 부분문자열의 최소 길이이다.

그런데 만약 len-pi[len]이 len으로 나누어 떨어진다면? len은 위에서 말한 부분문자열로만 이루어져있는 것이다.

따라서 위의 예시처럼 text[0~len-pi[len]]만큼의 부분문자열이 반복되는 것을 볼수 있다.


한편, len-pi[len]이 len으로 나누어떨어지지 않는다면?

혹은 len-pi[len]이 len의 절반보다 크다면?

다음 예를 보자.

 

 문자열

 pi[len] 

 abcab

 abkkab

 abcabcabc


abcab의 경우는 나누어떨어지지 않는 경우이다. 이처럼 문자열 중간에 찌꺼기가 들어있으면 나누어 떨어지지 않는다.

abkkab의 경우는 len-pi[len]이 len의 절반보다 큰 경우이다. 부분 문자열이 문자열의 모든 부분을 차지하고 있지 않을 경우 이렇게 나타난다.

abcabcabc의 경우는 올바른 경우다. 


코드는 다음과 같다.


//deque.tistory.com
#define _CRT_SECURE_NO_WARNINGS
#include <iostream> 
#include <string> 
#include <cstring>
using namespace std;
int pi[1000002];
int main() {
	while (true) {
		string str;
		getline(cin, str);
		if (str == ".") break;
		memset(pi, 0, sizeof(pi));
		int strLength = str.size();
		int j = 0;
		for (int i = 1; i < strLength; i++) {
			while (j > 0 && str[i] != str[j]) j = pi[j - 1];
			if (str[i] == str[j]) pi[i] = ++j;
		}
		int patternLen = pi[strLength - 1];
		if (strLength / 2 > patternLen && strLength % (strLength - patternLen) != 0) printf("%d\n", 1);
		else printf("%d\n", strLength / (strLength - patternLen));
	}
	return 0;
}








'코딩 > 알고리즘' 카테고리의 다른 글

백준 11478 서로 다른 부분 문자열의 개수  (0) 2018.01.14
백준 9248 Suffix Array  (0) 2018.01.14
백준 1701 Cubeditor  (0) 2018.01.12
[python3] 백준 1786 찾기  (0) 2018.01.12
백준 1015 수열 정렬  (0) 2018.01.10