算法题:给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,如把字符串“abcdef”前面的2个字符’a’和’b’移动到字符串的尾部,使得原字符串变成字符串“cdefab”。请写一个函数完成此功能,要求对长度为n的字符串操作的时间复杂度为 O(n),空间复杂度为 O(1)。
最开始想到的就是将整个数组前移两次。符合空间复杂度O(1)。
#include<iostream>
using namespace std;
//abccddee
void LeftMove(char * chars, int length) {
int temp = *chars;
for (int i = 0; i < length - 1; i++) {
*(chars + i) = *(chars + i + 1);
}
*(chars + length - 1) = temp;
}
void RevertString(int begin, int end, char * chars);
int main() {
char targets[9] = "abccddee";
//RevertString(0, 1, targets);
//RevertString(2, 7, targets);
//RevertString(0, 7, targets);
LeftMove(targets, 8);
LeftMove(targets, 8);
cout << targets << endl;
cin >> targets;
}
显然时间复杂度是O(2n),若是前m位移动到字符串后面,时间复杂度将是O(m*n)。
网上查到一种通过翻转的思想来解这道题。众所周知,一串数字翻转的翻转则是它本身。
ab翻转得:ba。
ccddee翻转得:eeddcc。
abccddee翻转得:eeddccba。
显然我们只需要翻转一次ab,再翻转一次ccddee,再翻转一次abccddee,即可得到正确解。
ab->ba;
ccddee->eeddcc;
baeeddcc->ccddeeab;
就有了下面的代码:
void RevertString(int begin, int end, char * chars);
int main() {
char targets[9] = "abccddee";
RevertString(0, 1, targets);
RevertString(2, 7, targets);
RevertString(0, 7, targets);
//LeftMove(targets, 8);
//LeftMove(targets, 8);
cout << targets << endl;
cin >> targets;
}
void RevertString(int begin, int end, char * chars) {
int length = end - begin + 1;
char temp;
for (int i = 0; i < length / 2; i++) {
temp = *(chars + begin + i);
*(chars + begin + i) = *(chars + end - i);
*(chars + end - i) = temp;
}
}
显然这种算法的时间复杂度为O(n),扩展下思维,凡是处理类似数组一部分移到另一处的问题,都可以用这种多次翻转的思路实现。