参考了http://kenby.iteye.com/blog/1451910
http://blog.csdn.net/sunnyyoona/article/details/25918163
有时候看编程之美里面的算法题,觉得他们怎么能够想到这么精妙的idea.
字符串移位包含问题
题目
给定两个字符串 s1 和 s2, 要求判定 s2 是否能够被通过 s1 作循环移位 ( rotate )
得到的字符串包含. 例如, 给定 s1 = AABCD 和 s2 = CDAA, 返回 true; 给定
s1 = ABCD 和 s2 = ACBD, 返回 false.
1.暴力的方法,
每次不断的移位s1,判断s2是否在s1中
这种方法效率很低
2.从规律出发
以S1 = ABCD为例,先分析对S1进行循环移位之后的结果,如下所示:
ABCD--->BCDA---->CDAB---->DABC---->ABCD……
假设我们把前面的移走的数据进行保留,会发现有如下的规律:
ABCD--->ABCDA---->ABCDAB---->ABCDABC---->ABCDABCD……
因此,可以看出对S1做循环移位所得到的字符串都将是字符串S1S1的子字符串。如果S2可以由S1循环移位得到,那么S2一定在S1S1上,这样时间复杂度就降低了
在http://blog.csdn.net/sunnyyoona/article/details/25918163中给出了代码。
注意其中的strcat函数。
3.还可以折中的想法。
单独每次拿s1中的一个字符和s2中的一个字符进行比较。如果相等两者就往后移(s1可以循环,所以要对s1的长度取余),如果不相等,就s1跳到下一位,而s2从0开始。代码如下。
- int main()
- {
- char src[] = "AEBBCD";
- char des[] = "CDAE";
- int len_src = strlen(src);
- int len_des = strlen(des);
- int i, j, k;
- for (i = 0; i < len_src; i++) {
- j = i;
- k = 0;
- while (src[j] == des[k]) {
- j = (j + 1) % len_src;
- k++;
- }
- if (k == len_des) {
- printf("Yes\n");
- getchar();
- return 1;
- }
- }
- printf("No\n");
- getchar();
- return 0;
- }
参照暴力解发的代码
int main()
{
char src[] = "AEBBCD";
char des[] = "AFB";
int len_src = strlen(src);
int len_des = strlen(des);
int i=0, j=0;
while((i<len_src)&&(j<len_des)) {
if(src[i]==des[j])
{
i=(++i)%len_src;
j++;
}
else
{
j=0;
if((i-j+1+len_src)>len_src)
break;
i=(i-j+1+len_src)%len_src;
}
}
if(j==len_des)
printf("yes\n");
if(j<len_des)
printf("No\n");
return 0;
}
我觉得kmp的next方法可以参照过来用,但是可能问题在于判断边界,即何时跳出