标签:
如果暴力解决的话,时间复杂度应为:O(n^2).
采用字符串哈希,时间复杂度为:O(n*lgn).
采用KMP算法的next数组,时间复杂度为:O(n).
我用字符串哈希(bkdhash)写的,虽然不及kmp,但还是粘上吧:
#include<iostream> using namespace std; typedef unsigned long long ull; char arr[1000001]; ull nbase[1000001]; ull Hash[1000001]; int base = 31; void main() { nbase[0] = 1; for (int i = 1; i < 1000001; ++i) nbase[i] = nbase[i - 1] * base; while (scanf_s("%s", arr, 1000001)) { int len = strlen(arr); ull n = 0; Hash[len] = 0; for (int i = len - 1; i >= 0; --i) Hash[i] = Hash[i + 1] * base + arr[i] - 'a' + 1; for (int k = 1; k <= len; ++k) { if (len%k != 0) continue; ull temp = Hash[0] - Hash[k] * nbase[k]; int j = 0; for (j = k; j < len; j = j + k) { if (temp != Hash[j] - Hash[j + k] * nbase[k]) break; else temp = Hash[j] - Hash[j + k] * nbase[k]; } if (j == len) { n = len / k; break; } } cout << n; } }
关于bkdhash:http://blog.csdn.net/wanglx_/article/details/40400693
我自己的直观的理解:
为了方便说明,
假设:base = 3,数的范围为0-63 (代码中实际情况是,base=31,数据类型为unsigned long long)
对于字符串abcabc:
index: 0 1 2 3 4 5
arr: a b c a b c
hash: 56 61 41 34 11 3 (计算公式:hash[i]=hash[i+1]*base+arr[i]-‘a‘+1) 这里面有个问题是:因为数的范围为0-63 ,最大为63,可能存在数的溢出,比如:
从右往左,a->c这一步,hash[2] = hash[3]*3+‘c‘-‘a‘+1 =34*3+2+1= 105。105大于63,这么办?
在计算机中会自动取模(也就是取余数):105% 64=41。其他hash值都是这么计算的,每步都会取余数的。
同样, nbase的计算也是如此:3 9 27
17(81%64) ......
那么计算机怎么判断前三个字符("abc")与后三个字符("abc")相等呢?取模后计算会不会出现负值?
后三个字符:temp0 = hash[3]-hash[6]*nbase[3] = 34 - 0*27 = 34
前三个字符:temp1 = hash[0]-hash[3]*nbase[3] = 56 -34*27 = ? 。这里34*27实际是(34*27)%64=22,所以56-22=34。
所以temp0=temp1。
关于使用KMP算法的next数组,我是这么想的:
(kmp:http://blog.csdn.net/v_july_v/article/details/7041827#comments)
写的我自己都看不懂了...
代码如下:
#include<iostream> using namespace std; int getNext(char* arr, int len) //返回最后一个值:next[len-1] { int* next = new int[len]; memset(next, 0, len*sizeof(int)); for (int i = 1; i < len; ++i) { int p = next[i - 1]; while (p > 0 && arr[i] != arr[p]) p = next[p - 1]; if (p == 0 && arr[i] != arr[p]) //当p == 0 && arr[i] != arr[p]时,单独考虑:next[i] = 0。 next[i] = 0; else next[i] = p + 1; } return next[len - 1]; } void main() { char arr[1000001] = { '\0' }; while (scanf_s("%s", arr, 1000001)) { int len = strlen(arr); int next = getNext(arr, len); if (len % (len - next) == 0) cout << len / (len - next) << endl; else cout << 1 << endl; } }
POJ 2406 Power Strings--字符串哈希(bkdhash)
标签:
原文地址:http://blog.csdn.net/u011567017/article/details/51353786