首先说明下所谓"字符串左右旋转"是指什么:
如字符串"abcdefg"左旋2位,结果应该是"cdefgab";再对"cdefgab"右旋2位,结果应该是"abcdefg",即:
左旋n位:字符串的前n位由首部移到尾部,右旋n位:字符串的后n位由尾部移到首部。n < strlen(字符串)
1、直观的常规方法:
直观方法就是依次移位,比如abcdefg,需要左旋2位,那么先把a移位到尾部使字符串变成bcdefga,然后再把b移位到尾部是字符串变成cdefgab。
每个字符的一次直接移位的时间复杂度是O(N),如果需要移位n个字符,那么时间复杂度就是O(n * strlen(字符串))
2、O(N)的方法:
采取"先交换最后移位"的方式,依然以abcdefg左旋2位为例,先连续进行2次"交换",依次变为cdabefg、cdefabg,这时候长度已经不能再交换了,就对最后的abg进行移位变为gab,最终结果就是cdefgab。交换、移位的时间复杂度都是O(N),所以整个操作的时间复杂度也是O(strlen(字符串)):
完整程序含测试程序如下:
#include <iostream>
#include <stdlib.h>
//p[0: num-1]与p[num: num * 2 - 1]交换数据(O(N))
void swap (char *p, int num) {
for (int i = 0; i < num; i++) {
char tmp = p[i];
p[i] = p[i + num];
p[i + num] = tmp;
}
}
//abcde变为eabcd(O(N))
void leftshift (char *p, int num) {
char rightest = p[num];
for (int i = num; i > 0; i--) {
p[i] = p[i - 1];
}
p[0] = rightest;
}
//abcde变为bcdea(O(N))
void rightshift (char *p, int num) {
char leftest = p[0];
for (int i = 0; i < num; i++) {
p[i] = p[i + 1];
}
p[num] = leftest;
}
//还能整块交换的时候就整块交换, 不能交换的时候就移位. rotate和shift的时间复杂度都是O(N), 所以整个操作也是O(N)的时间复杂度
void leftrotate (char *p, const char *q, int num) {
//当前指针离字符串末尾如果不足两倍交换的长度, 就该移位了. 否则继续整块交换
if (q - p >= (num * 2)) {
swap(p, num);
p = p + num;
leftrotate(p, q, num);
} else {
for (int i = 0; i < num; i++) {
rightshift(p, q - p);
}
return;
}
}
void rightrotate (char *p, const char *q, int num) {
if (p - q >= (num * 2)) {
swap(p - num * 2 + 1, num);
p = p - num;
rightrotate(p, q, num);
} else {
for (int i = 0; i < num; i++) {
leftshift(p - (p - q), p - q);
}
}
}
int main (int argc, char *argv[]) {
char *raw = argv[1];
char *res = new char(strlen(raw) + 1);
memcpy(res, raw, strlen(raw));
res[strlen(raw)] = '\0';
std::cout << res << std::endl;
int num = atoi(argv[2]);
leftrotate(res, (const char *)&res[strlen(res) - 1], num);
std::cout << res << std::endl;
rightrotate(&res[strlen(res) - 1], (const char *)res, num);
std::cout << res << std::endl;
delete res;
return 0;
}