题目:定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部。
如把字符串abcdef左旋转2位得到字符串cdefab。
请实现字符串左旋转的函数,要求对长度为n的字符串操作的时间复杂度为O(n),空间复杂度为O(1)。
思路:其实这种题目很好解。直接对每个位置迭代求数据来源位置就可以了。有另外一些解法,比如交换法,双反转法,递归法,对于解此题目没什么高效的解法。我认为以下解法完全满足题目要求,是最佳的。
void rotate_left_string(char * src, int m)
{
int n = strlen(src);
if ( n && ( m = (m%n+n)%n ) )
{
//m为负值的情况也已经考虑
char t = src[0];
int k = 0;
int i = 0;
int l = n-1;//最后一个值单独填回t值,所以要少一次循环
while (l--)
{
k = (i+m)%n;//迭代找目前i位置应该填的值
src[i]=src[k];
i = k;
}
src[i] = t;//填充最后一个值
}
}
以上解法有一个严重的问题:当m,n不互质的时候会引起重叠覆盖的情况,谢谢评论指出。
原回复代码由primerplus给出:
#include <iostream>
using namespace std;
int gcd(int m, int n) {
if (m < n)
return gcd(n, m);
while (n) {
int t = m % n;
m = n;
n = t;
}
return m;
}
void rotate_left_string(char *a, int m)
{
int n = strlen(a);
int l = gcd(n, m);
for (int i = 0; i < l; ++i) {
char t = a[i];
int pre = i;
int next = (i+m) % n;
while (next != i) {
a[pre] = a[next];
pre = next;
next = (next + m) % n;
}
a[pre] = t;
}
}
int main()
{
int m;
while (1) {
cin >> m ;
char s[13] = "abc123456789";
rotate_left_string(s, m);
cout << s << endl;
}
return 0;
}