题目:
给定2个字符串srt1和str2,实现一个算法判断其是否互为旋转字符串。
注:
比如字符串”ABCDE” 那么”BCDEA” “CDEAB” “DEABC” “EABCD”都是其旋转字符串。
思路:
这里我们判断str2是否是str1的旋转字符串。
①. 如果str1和str2的长度都不相等,那么肯定返回false,不需要执行下面的操作。
② . str1和str2的长度相等
我们可以按照旋转字符串的定义,对str2进行旋转移位,并判断移位后的字符串是否与str1相等。这样最多需要执行n-1次这样的操作。【n是给定字符串的长度】
下面给出另外一种O(N)复杂度的算法,基于KMP的字符串模式匹配。
举例说明:对于str1 = “ABCD” str2 = “BCDA”
那么 新生成一个新字符串str3 = str1 + str1; 可以看到:
str3 = “ABCDABCD” 这其中包含了所有可能的旋转字符串 即: BCDA CDAB DABC
因此 接下来的操作就是判断str3中是否str2这样的子串,属于字符串匹配问题。可以由KMP算法求解。
贴代码:
<span style="font-size:14px;">#include <iostream>
#include <string>
#include <vector>
using namespace std;
bool chkRotation(const string A, const int lena, const string B, const int lenb);
void nextArr(const string str, vector<int> &v);
int KMP(const string str, const string mode);
bool chkRotation(const string A, const int lena, const string B, const int lenb)
{
return (KMP(A + A, B) != -1);
}
// 求next数组v
void nextArr(const string str, vector<int> &v)
{
// 字符串长度为1 直接返回 [-1]
if (str.length() == 1)
{
v[0] = -1;
return;
}
// 前两个字符的next值分别为 -1 0
v[0] = -1;
v[1] = 0;
unsigned int pos = 2, cnt = 0;
while(pos < v.size())
{
if (str[pos - 1] == str[cnt])
{
v[pos++] = ++cnt;
}
else if(cnt > 0)
{
cnt = v[cnt];
}
else
{
v[pos++] = 0;
}
}
}
int KMP(const string str, const string mode)
{
// 异常检查
if (str.empty() || mode.empty() || mode.length() < 1 || str.length() < mode.length())
{
return -1;
}
// next数组长度只与模式串有关
vector<int> next(mode.length());
// 获取next数组
nextArr(mode, next);
unsigned int idx = 0, modeIdx = 0;
while(idx < str.length() && modeIdx < mode.length())
{
if (str[idx] == mode[modeIdx])
{
idx++;
modeIdx++;
}
else if (next[modeIdx] == -1)
{
idx++;
}
else
{
modeIdx = next[modeIdx];
}
}
return ((modeIdx == mode.length()) ? (idx - modeIdx) : -1);
}
int main(void)
{
string s1 = "1234", s2 = "2341";
int len1 = s1.length(), len2 = s2.length();
if (chkRotation(s1, len1, s2, len2))
{
cout<<"YES : s1 and s2 are rotated string"<<endl;
}
else
{
cout<<"NO : s1 and s2 are not rotated string"<<endl;
}
return 0;
}</span>
输出: