字符串轮转。给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成(比如,waterbottle是erbottlewat旋转后的字符串)。
示例1:
输入:s1 = “waterbottle”, s2 = “erbottlewat”
输出:True
示例2:
输入:s1 = “aa”, “aba”
输出:False
提示:
字符串长度在[0, 100000]范围内。
说明:
你能只调用一次检查子串的方法吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/string-rotation-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解:
思路一:
暴力法:
- 如果s2是由s1旋转而来 则从头到尾开始旋转s1
- 遍历旋转0位(原串), 1位…直至最后
- 如果遍历构成中,有跟s2相同的字符串,则return true
- 遍历一遍完后,都没有相同字符串,则return false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// 暴力法
// 如果 s2 是由 s1 旋转而来 则从头到位开始旋转s1
// 遍历旋转0位(原字串), 1位... 直到旋转到倒数第二位
// 如果遍历过程中,有跟s2相同的字符串, 则return true
// 遍历一遍完后,都没有相同字符串, 则return false
public boolean isFlipedString1(String s1, String s2) {
if ((s1 == null && s2 == null) || (s1.length() == 0 && s2.length() == 0)) return true;
if (s1 == null || s2 == null) return false;
if (s1.length() != s2.length()) return false;
int i = 0;
StringBuilder sb = new StringBuilder();
while (i < s1.length()){
sb.delete(0,sb.length());
sb.append(s1.substring(i, s1.length()));
sb.append(s1.substring(0,i));
if (sb.toString().equals(s2)) return true;
i++;
}
return false;
}
|
此方法执行时间38ms, 有大量的拼接,比较操作。
思路二:
-
题目中有说明, 你能只调用一次检查子串的方法吗?
-
显然上述解题,不符合检查一次字串的要求。拼接了N次字串,比较了N次字串
-
上述方法时间复杂度 : O(N ^ 2)
-
空间复杂度 : O(1)
-
时间复杂度非常高,算法虽过了,但是用时很长
-
接下来,我们尝试做时间复杂度的优化
-
思路是 裁剪字串成两个子串
-
从头到位比较,当字串s1 i位置, 与字串s2的0位置,字符相同时,根据i分割两个字串
-
如果s1 和 s2 分割后,两部分分别都相同,说明是旋转字串
-
如果不相同, 则往下遍历下一个与 s2 0位置相同的元素。
-
i遍历完, 即与s2 0号位置相同的字符又两部分分别相同的字串。 则return false
-
我们的时间复杂度有了大幅度的提升,截图中可以看出,由之前的40ms左右,提高到1ms左右。
-
时间复杂度 : O(N)
-
空间复杂度 : O(1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
// 题目中有说明, 你能只调用一次检查子串的方法吗?
// 显然上述解题,不符合检查一次字串的要求。拼接了N次字串,比较了N次字串
// 上述方法时间复杂度 : O(N ^ 2)
// 空间复杂度 : O(1)
// 时间复杂度非常高,算法虽过了,但是用时很长
// 接下来,我们尝试做时间复杂度的优化
// 思路是 裁剪字串成两个子串
// 从头到位比较,当字串s1 i位置, 与字串s2的0位置,字符相同时,根据i分割两个字串
// 如果s1 和 s2 分割后,两部分分别都相同,说明是旋转字串
// 如果不相同, 则往下遍历下一个与 s2 0位置相同的元素。
// i遍历完, 即与s2 0号位置相同的字符又两部分分别相同的字串。 则return false
// 我们的时间复杂度有了大幅度的提升,截图中可以看出,由之前的40ms左右,提高到1ms左右。
// 时间复杂度 : O(N)
// 空间复杂度 : O(1)
public boolean isFlipedString2(String s1, String s2){
if ((s1 == null && s2 == null) || (s1.length() == 0 && s2.length() == 0)) return true;
if (s1 == null || s2 == null) return false;
if (s1.length() != s2.length()) return false;
int i = 0,len = s1.length();
while ((i < len)){
if (s1.charAt(i) != s2.charAt(0)){
i ++;
continue;
}
String l_s1 = s1.substring(0,i);
String r_s1 = s1.substring(i,len);
String l_s2 = s2.substring(0,len - i);
String r_s2 = s2.substring(len - i,len);
if (l_s1.equals(r_s2) && r_s1.equals(l_s2)) return true;
i++;
}
return false;
}
|
思路三:
- 以下为leetcode大神解题思路
- 如果 s2 是由 s1旋转而来,则 s1 + s1 必然包含 s2 ⚠️⚠️⚠️
- 想到了字符串拼接可能能解决问题,没想到这种思路
- 感觉费半天劲,牛逼的思路一行代码搞定了,差距非常大啊😓😓😓
- 非常6,双百操作。
1
2
3
4
5
6
|
public boolean isFlipedString(String s1, String s2){
if ((s1 == null && s2 == null) || (s1.length() == 0 && s2.length() == 0)) return true;
if (s1 == null || s2 == null || s1.length() != s2.length()) return false;
return (s1 + s1).contains(s2);
}
|