问题:将一个n元一维向量向左旋转i个位置。例如,当n=8且i=3时,向量abcdefgh旋转为defghabc。简单的代码使用一个n元中间量在n步内完成该工作,你能否仅使用数十个额外字节的存储空间,在正比于n的时间内完成向量的旋转?
Brute Algorithm:
将需要移动的字符串x前i个元素复制到一个临时字符串数组中,然后将剩下n-i个元素向前移动i个单位,最后将临时字符串数组中的元素复制到x余下的位置中。
#include <iostream> #include <string> using namespace std; void reverse(string& str, int index) { int size = str.size(); int t = size - index; string strtmp(str.begin(), str.begin() + index); for (int j = 0; j != t; j++) swap(str[j], str[j + index]); for (int x = t, y = 0; x != size; x++) str[x] = strtmp[y++]; } int main() { string str("abcdefgh"); reverse(str, 3); cout << str; return 0; }
Fantastic Algorithm 1:
首先将x[0]与x[0 + i]交换,x[0 + i]与x[0 + 2i]交换,依次往后交换。在这个过程中,若x的索引大于n,则令k = k - n,直到k = i终止循环。
求出n与i的最大公约数,这个数time是外层循环i的次数。
int gcd(int i, int j) { while (i != j) { if (i > j) i -= j; else j -= i; } return i; }
#include <iostream> #include <string> using namespace std; int gcd(int a, int b) { int tmp = 0; while (b != 0) { tmp = b; b = a % b; a = tmp; } return a; } void reverse(string& str, int index) { int size = str.size(); int time = gcd(size, index); for (int i = 0; i != time; i++) { int j = i; do { int k = j + index; if (k >= size) k -= size; if (k == i) break; swap(str[j], str[k]); j = k; } while (1); } } int main() { string str("abcdefgh"); reverse(str, 3); cout << str; return 0; }
Fantastic Algorithm 2:
将字符串数组分成2个部分,分别对两个部分进行反转,最后对整个字符串数组进行反转即可。
#include <iostream> #include <string> using namespace std; void reverse(string& str, int l, int r) { string tmp; for (int i = r; i >= l; i--) { tmp.push_back(str[i]); } for (int i = l, j = 0; i <= r; i++) str[i] = tmp[j++]; } int main() { string str("abcdefgh"); int i = 3, n = 8; reverse(str, 0, i - 1); reverse(str, i, n - 1); reverse(str, 0, n - 1); cout << str; }