이거 그 유명한 Algorithms on strings, trees and sequences 책의 연습 문제 중 하나입니다.
For each of the n prefixes of P, we want to know whether the prefix P[1..i] is a periodic string. That is, for each I we want to know the largest k > 1 (if there is one) such that P[1..i] can be written as αk for some string α. Of course, we also want to know the period. Show how to determine this for all n prefixes in time linear in the length of P.
Hint: Z-algorithm
저는 풀긴했는데 왜 되는건지 저도 잘 -_-;
너무 복잡하게 푼거 같네요.
이름을 modified-z value 라고 지어서 처리했는데, 사실 Z-algorithm 하고는 별 상관없고.. (처음 의도는 그랬지만 결국 상관없게 되버린..)
O(n)이라는건 돌려보면 쉽게 알 수 있습니다. 그게 아니라도 그냥 for 문만 봐도 i가 n까지만 돌아가니까 알 수 있어요.
#include<stdio.h>
#include<malloc.h>
#include<string.h>
// dump modified_z values
void dump(const char *p, int *modified_z, int len);
// print periods of P
void print_periods(int *modified_z, int len);
int main()
{
const char *p = "abcabcd";
int *modified_z = (int *) calloc(strlen(p), sizeof(int));
int i, j, z_index;
printf("P: %s\n", p);
for (i=1, j=z_index=0 ; i < strlen(p) ; )
{
int z_index = i;
{
printf("comparing p[%d]=%c / p[%d]=%c\n", i, p[i], j, p[j]);
if (p[i] == p[j])
{
modified_z[z_index]++;
j++; i++;
}
else {
z_index = i;
i++;
j=0;
}
}
}
dump(p, modified_z, strlen(p));
print_periods(modified_z, strlen(p));
return 0;
}
void print_periods(int *modified_z, int len)
{
int i;
int sum = 0;
int non_zero = -1;
int alpha_len = 0;
for (i = 0 ; i < len ; i++)
{
if (modified_z[i] == 0)
{
non_zero = -1;
sum = 0;
alpha_len = 0;
}
else if (modified_z[i] != 0 && non_zero == -1)
{
non_zero = i;
}
if (modified_z[i] != 0)
{
sum += modified_z[i];
if (non_zero == sum)
{
if (alpha_len == 0) alpha_len = non_zero;
printf("P[1..%d] is alpha^%d.\n", i+1, (i+1)/alpha_len);
printf("Got alpha. So, change non_zero from %d to -1\n", non_zero);
non_zero=-1;
}
}
printf("i=%d non_zero=%d alpha_len=%d sum=%d\n", i, non_zero, alpha_len, sum);
}
}
void dump(const char *p, int *modified_z, int len)
{
int i;
for (i = 0 ; i < len ; i++)
printf("%c\t modified_z[%d] = %d\n", p[i], i+1, modified_z[i]);
}
// If this is the first time to find non zero MZ value
else if (modified_z[i] != 0 && non_zero == -1)
{
// Remember the position where non zero MZ value were found
non_zero = i;
}
// Non zero MZ position is found
if (modified_z[i] != 0)
{
// Compute the number of successive matches
sum += modified_z[i];
// If the start of non zero position equals to the number of
// successive matches.
if (non_zero == sum)
{
// If this is the first time we found match after (1)
// set the length of alpha as non_zero
if (alpha_len == 0) alpha_len = non_zero;
// Print matching information
printf("Matching found\n");
printf("P[1..%d] is alpha^%d.\n", i+1, (i+1)/alpha_len);
// We want to find the next match
non_zero=-1;
}
}
printf("i=%d non_zero=%d alpha_len=%d sum=%d\n", i, non_zero, alpha_len, sum);
}
}
// Show me the contents of MZ
void dump(const char *p, int *modified_z, int len)
{
int i;
for (i = 0 ; i < len ; i++)
printf("%c\t modified_z[%d] = %d\n", p[i], i+1, modified_z[i]);
}
Post a Comment