题目:给定一个长度为 n n n 的字符串 s s s,将 s s s 进行循环右移 k k k 位。
显然,将字符串循环右移 n n n 位后,得到原字符串。循环移动 k k k 位与循环移动 k m o d n k \mod n kmodn 位后的字符串相同。
对 s s s 进行循环右移 k k k 位,相当于:截取 s s s 的后 k k k 个字符,将其连接到剩下的子串的开头。
void rotateRight(string &s, int k){
int n = s.size();
k %= n;
if(k==0) return;
string sub1 = s.substr(0, n-k); // 截取 s 的前 n-k 个字符
string sub2 = s.substr(n-k); // 截取 s 的后 k 个字符
s = sub2 + sub1;
}
或者按照数组的方式,访问并确定 s s s 的每个字符。
void rotateRight(string &s, int k){
int n = s.size();
k %= n;
if(k==0) return;
string tmp = s;
for(int i=0; i<k; ++i){ // 确定前 k 个字符是原字符串的后 k 个字符
s[i] = tmp[i+n-k];
}
for(int i=k; i<n; ++i){ // 确定后 n-k 个字符是原字符串的前 n-k 个字符
s[i] = tmp[i-k];
}
}
上面程序的时间复杂度是 O ( n ) O(n) O(n),空间复杂度是 O ( n ) O(n) O(n)。
令 0 < k < n 0
三步翻转法可以实现数组循环右移操作,其时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( 1 ) O(1) O(1)。
void rotateRight(string &s, int k){
int n = s.size();
k %= n;
if(k==n) return;
reverse(s.begin(), s.begin()+n-k);
reverse(s.begin()+n-k, s.end());
reverse(s.begin(), s.end());
}
存在等效方法:
可以这么理解:
nums = "----->-->"; k =3
result = "-->----->";
reverse "----->-->" we can get "<--<-----"
reverse "<--" we can get "--><-----"
reverse "<-----" we can get "-->----->"
this visualization help me figure it out :)
上面的模拟来源于 leetcode 题189. 旋转数组官方题解下的评论。
下面是 C++ 代码实现:
void rotateRight(string &s, int k){
int n = s.size();
k %= n;
if(k==n) return;
reverse(s.begin(), s.end());
reverse(s.begin(), s.begin()+k);
reverse(s.begin()+k, s.end());
}
reverse(first, last)
函数模板在定义在头文件
中,功能是反转 [first, last) 范围内元素的顺序。它的时间复杂度是 O ( n ) O(n) O(n),空间复杂度是 O ( 1 ) O(1) O(1), n n n 是 first 到 last 之间的距离。
也可以自己实现 reverse() 函数的功能。
#include
using namespace std;
// 反转字符串 s 的范围 [left, right] 内字符的顺序
void reverseString(string &s, int left, int right){
while(left<right){
char tmp = s[left];
s[left] = s[right];
s[right] = tmp;
++left;
--right;
}
}
// 将字符串 s 进行循环右移 k 位
void rotateRight(string &s, int k){
int n = s.size();
k %= n;
if(k==n) return;
reverseString(s, 0, n-1);
reverseString(s, 0, k-1);
reverseString(s, k, n-1);
}
int main(){
string s = "12345678";
rotateRight(s, 3);
cout << s << endl; // 输出 67812345
return 0;
}
如果题目要求将长度为 n n n 的字符串 s s s 循环左移 k k k 位,即求:将 s s s 循环右移 n − k n-k n−k 位。
刷题题解目录