剑指Offer58-II.左旋转字符串
反转个字符串还有这么多用处?
1 题目
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
示例 1:
输入: s = “abcdefg”, k = 2
输出: “cdefgab”
示例 2:
输入: s = “lrloseumgh”, k = 6
输出: “umghlrlose”
限制:
1 <= k < s.length <= 10000
2 思路
通过局部反转+整体反转 达到左旋转的目的。
具体步骤为:
反转区间为前n的子串反转区间为n到末尾的子串反转整个字符串
最后就可以达到左旋n的目的,而不用定义新的字符串,完全在本串上操作。
例如 :示例1中 输入:字符串abcdefg,n=2

3 代码
3.1 C++版本
class Solution {
public:
string reverseLeftWords(string s, int n) {
reverse(s.begin(), s.begin() + n); //前闭后开
reverse(s.begin() + n, s.end());
reverse(s.begin(), s.end());
return s;
}
};
3.2 C版本
char* reverse(char* s, int start, int end) {
while (start < end) {
char temp = s[start];
s[start++] = s[end];
s[end--] = temp;
}
return s;
}
char* reverseLeftWords(char* s, int n){
int len = strlen(s);
//反转前 n 个字符
s = reverse(s, 0, n - 1);
//反转 k 到末尾的字符
s = reverse(s, n, len - 1);
//反转整个字符串
s = reverse(s, 0, len - 1);
return s;
}
3.3 Java版本
//思路为:先整个字符串反转,再反转前面的,最后反转后面 n 个
class Solution {
public String reverseLeftWords(String s, int n) {
char[] chars = s.toCharArray();
reverse(chars, 0, chars.length - 1);
reverse(chars, 0, chars.length - 1 - n);
reverse(chars, chars.length - n, chars.length - 1);
return new String(chars);
}
public void reverse(char[] chars, int left, int right) {
while (left < right) {
chars[left] ^= chars[right];
chars[right] ^= chars[left];
chars[left] ^= chars[right];
left++;
right--;
}
}
3.4 Python版本
方法一:可以使用切片方法
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
return s[n:] + s[0:n]
方法二:也可以使用上文描述的方法
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
s = list(s)
s[0:n] = list(reversed(s[0:n]))
s[n:] = list(reversed(s[n:]))
s.reverse()
return "".join(s)
3.5 JavaScript版本
var reverseLeftWords = function(s, n) {
const length = s.length;
let i = 0;
while (i < length - n) {
s = s[length - 1] + s;
i++;
}
return s.slice(0, length);
};
版本二(在原字符串上操作):
/**
* @param {string} s
* @param {number} n
* @return {string}
*/
var reverseLeftWords = function (s, n) {
/** Utils */
function reverseWords(strArr, start, end) {
let temp;
while (start < end) {
temp = strArr[start];
strArr[start] = strArr[end];
strArr[end] = temp;
start++;
end--;
}
}
/** Main code */
let strArr = s.split('');
let length = strArr.length;
reverseWords(strArr, 0, length - 1);
reverseWords(strArr, 0, length - n - 1);
reverseWords(strArr, length - n, length - 1);
return strArr.join('');
};
4 总结
这个思路类似的题我在王道数据结构和算法的练习题也刷到过。
只要思路打开了就很简单。
也可以先反转整个字符串,再反转后n个子串和剩下前面的字串。
一些同学热衷于使用substr,来做这道题。 其实使用substr 和 反转 时间复杂度是一样的 ,都是O(n),但是使用substr申请了额外空间,所以空间复杂度是O(n),而反转方法的空间复杂度是O(1)。
如果想让这套题目有意义,就不要申请额外空间。
此时我们已经反转好多次字符串了,来一起回顾一下吧。
在这篇文章【字符串】leetcode344.反转字符串(C/C++/Java/Python/Js),第一次讲到反转一个字符串应该怎么做,使用了双指针法。
然后发现【字符串】leetcode541. 反转字符串II(C/C++/Java/Python/Js),这里开始给反转加上了一些条件,当需要固定规律一段一段去处理字符串的时候,要想想在for循环的表达式上做做文章。
后来在【字符串】leetcode151.翻转字符串里的单词(C/C++/Java/Python/Js)中,要对一句话里的单词顺序进行反转,发现先整体反转再局部反转 是一个很妙的思路。
最后再讲到本题,本题则是先局部反转再 整体反转,与【字符串】leetcode151.翻转字符串里的单词(C/C++/Java/Python/Js)类似,但是也是一种新的思路。
By – Suki 2023/2/5

1213

被折叠的 条评论
为什么被折叠?



