算法之将字符串的部分移动

  算法题:给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,如把字符串“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),扩展下思维,凡是处理类似数组一部分移到另一处的问题,都可以用这种多次翻转的思路实现。

点赞