LeetCode796. 旋转字符串(从业务思想到算法思想)
原创
©著作权归作者所有:来自51CTO博客作者秃秃爱健身的原创作品,请联系作者获取转载授权,否则将追究法律责任
796. 旋转字符串(简单)
给定两个字符串, s 和 goal。如果在若干次旋转操作之后,s 能变成 goal ,那么返回 true 。
s 的 旋转操作 就是将 s 最左边的字符移动到最右边。
例如, 若 s = 'abcde',在旋转一次之后结果就是'bcdea' 。
示例1:
输入: s = “abcde”, goal = “cdeab”
输出: true
示例2:
输入: s = “abcde”, goal = “abced”
输出: false
提示:
-
1 <= s.length, goal.length <= 100 -
s 和goal 由小写英文字母组成
解法一:暴力匹配
思路:
首先,如果 s 和 goal 的长度不一样,那么无论怎么旋转,s 都不能得到 goal,返回 false。
然后根据业务开发思想,按要求旋转字符串,再做字符串是否相等的判断。
代码(Java)
/**
* 方法一:暴力匹配
* 时间复杂度:O(n^2),其中 n 是字符串 s 的长度。我们需要双重循环来判断。
* 空间复杂度:O(n)。拼接字符串的空间
*/
public boolean rotateString(String s, String goal) {
int sLength = s.length();
int goalLength = goal.length();
if (sLength != goalLength) {
return false;
}
for (int i = 0; i < sLength; i++) {
char c = s.charAt(0);
String substring = s.substring(1);
s = substring + c;
if (s.equals(goal)) {
return true;
}
}
return false;
}
解法二:搜索子字符串
思路:
首先,一样的,如果 s 和 goal 的长度不一样,那么无论怎么旋转,s 都不能得到 goal,返回 false。
因为字符串 s+s 包含了所有 s 可以通过旋转操作得到的字符串,只需要检查goal 是否为 s + s 的子字符串即可。
代码(Java)
/**
* 方法二:搜索子字符串
* 时间复杂度:O(n),KMP算法搜索子字符串的时间复杂度为 O(n)
* 空间复杂度:O(n),KMP算法搜索子字符串的空间复杂度为 O(n)
*/
public boolean rotateString2(String s, String goal) {
return s.length() == goal.length() && (s + s).contains(goal);
}

附:最优版KMP算法实现
public boolean rotateString3(String s, String goal) {
return s.length() == goal.length() && knuthMorrisPrattMatch(s + s, goal) > -1;
}
/**
* 剪枝的效果
*
* @param s
* @return
*/
private int[] getNext(String s) {
int len = s.length(), i = 0, j = -1;
int[] next = new int[len];
next[0] = -1;
while (i < len - 1) {
if (j == -1 || s.charAt(i) == s.charAt(j)) {
++i;
++j;
// 当两个字符相等时要跳过
if (s.charAt(i) == s.charAt(j)) {
next[i] = next[j];
} else {
next[i] = j;
}
} else {
j = next[j];
}
}
return next;
}
/**
* 字符串匹配,返回匹配的模式串在主串中的起始位置
*
* @param sourceString 主串
* @param pattern 模式串
* @return
*/
public int knuthMorrisPrattMatch(String sourceString, String pattern) {
int sourceLen = sourceString.length(), patternLen = pattern.length();
int[] next = getNext(pattern);
int i = 0, j = 0;
while (i < sourceLen && j < patternLen) {
// 当j为-1时,要移动的是i,当然j也要归0
if (j == -1 || pattern.charAt(j) == sourceString.charAt(i)) {
j++;
i++;
} else {
// i = i - j + 1;
// i不需要回溯,j回到指定位置
j = next[j];
}
}
if (j == patternLen) {
return i - j;
}
return -1;
}
}