POJ 2406 Power Strings--字符串哈希(bkdhash)

如果暴力解决的话,时间复杂度应为: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;
	}
}
时间: 2024-12-06 21:16:46

POJ 2406 Power Strings--字符串哈希(bkdhash)的相关文章

POJ 2406 Power Strings (求字符串循环节出现的次数)

Power Strings Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 44217   Accepted: 18449 Description Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "

poj 2406 Power Strings KMP匹配

对于数组s[0~n-1],计算next[0~n](多计算一位). 考虑next[n],假设t=n-next[n],如果n%t==0,则t就是问题的解,否则解为1. 这样考虑: 比如字符串"abababab", a  b a b a b a b * next     -1 0 1 2 3 4 5 6  7 考虑这样的模式匹配,将"abababab#"当做主串,"abababab*"当做模式串,于是进行匹配到n(n=8)时,出现了不匹配: 主串   

POJ 2406 Power Strings KMP运用题解

本题是计算一个字符串能完整分成多少一模一样的子字符串. 原来是使用KMP的next数组计算出来的,一直都觉得是可以利用next数组的,但是自己想了很久没能这么简洁地总结出来,也只能查查他人代码才恍然大悟,原来可以这么简单地区求一个周期字符串的最小周期的. 有某些大牛建议说不应该参考代码或者解题报告,但是这些大牛却没有给出更加有效的学习方法,比如不懂KMP,难倒不应该去看?要自己想出KMP来吗?我看不太可能有哪位大牛可以直接自己"重新创造出KMP"来吧. 好吧,不说"创造KMP

poj 2406 Power Strings(kmp的nxt数组找最小循环节)

题目链接:poj 2406 Power Strings 题意: 给你一个字符串,让你找出这个字符串的最大循环次数,及最小循环节. 题解: 用kmp的nxt数组搞搞,L=j-nxt[j],为前缀j的最小循环节. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define F(i,a,b) for(int i=(a);i<=(b);++i) 5 using namespace std;

poj 2406 Power Strings(KMP&amp;思维)

Power Strings Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 31093   Accepted: 12974 Description Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "

poj 2406 Power Strings 后缀数组解法

连续重复子串问题 poj 2406 Power Strings http://poj.org/problem?id=2406 问一个串能否写成a^n次方这种形式. 虽然这题用kmp做比较合适,但是我们还是用后缀数组做一做,巩固后缀数组的能力. 对于一个串,如果能写出a^n这种形式,我们可以暴力枚举循环节长度L,那么后缀suffix(1)和suffix(1 + L)的LCP应该就是 lenstr - L.如果能满足,那就是,不能,就不是. 这题的话da算法还是超时,等我学了DC3再写上来. 其实这

poj 2406 Power Strings(KMP求循环次数)

题目链接:http://poj.org/problem?id=2406 Description Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "abcdef". If we think of concatenation as multiplication, e

poj 2406 Power Strings(kmp循环节)

题目链接:http://poj.org/problem?id=2406 题目大意:如果n%(n-next[n])==0,则存在重复连续子串,长度为n-next[n]. 例如:      a    b    a    b    a    b next:-1   0    0    1    2    3    4 next[n]==4,代表着,前缀abab与后缀abab相等的最长长度,这说明,ab这两个字母为一个循环节,长度=n-next[n]; 1 #include <iostream> 2

POJ - 2406 - Power Strings (字符串求周期--next函数的妙用)

题目传送:POJ - 2406 思路:就是利用kmp中next数组的特性来求最大周期的 AC代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1000005; char s[maxn]; int next[maxn]; int main() { while(scanf("%s", s) != EOF)

KMP + 求最小循环节 --- POJ 2406 Power Strings

Power Strings Problem's Link: http://poj.org/problem?id=2406 Mean: 给你一个字符串,让你求这个字符串最多能够被表示成最小循环节重复多少次得到. analyse: KMP之next数组的运用.裸的求最小循环节. Time complexity: O(N) Source code:  /** this code is made by crazyacking* Verdict: Accepted* Submission Date: 20