书中讲到三种方法,“杂技”交换、“求逆算法”和“块交换”法,注意形参一定要传引用!
“杂技”交换法:
void rotate1(string &str, int i) { set<int> s; int N = str.size(); int start = 0; while(s.size() != N) { int n = 0; int tmp = str[start]; while(((n+1)*i+start)%N != start) { str[(n*i+start)%N] = str[((n+1)*i+start)%N]; s.insert(((n+1)*i+start)%N); ++n; } str[(n*i+start)%N] = tmp; s.insert(start); if(s.size() != N) { ++start; n = 0; } else break; } }
时隔半年修改一下“杂技交换法”的实现,当时写的什么鬼,占用了这么多的辅助空间,实际上只要O(1)的辅助空间就可以了。
//"杂技交换法" char* rotate(char* pStr, int n) { if(pStr != NULL && n > 0) { int length = strlen(pStr); int countOfSwaped = 0; int startOfSwap = 0; int index = startOfSwap; while(countOfSwaped < length) { char temp = pStr[index]; int newIndex = (index+n) % length; while(newIndex != startOfSwap) { pStr[index] = pStr[newIndex]; ++countOfSwaped; index = newIndex; newIndex = (newIndex+n) % length; } pStr[index] = temp; ++countOfSwaped; if(countOfSwaped < length) index = ++startOfSwap; } } return pStr; }
之前并没有注意到题目里提到的最大公约数问题,如果利用最大公约数来确定循环次数,重新实现的算法如下:点击
“求逆”法:
void reverse(string &str, int start, int end) { int first = start; int last = end; while(first <= last) { char tmp = str[first]; str[first++] = str[last]; str[last--] = tmp; } } void rotate2(string &str, int i) { int n = str.size(); reverse(str, 0, i-1); reverse(str, i, n-1); reverse(str, 0, n-1); }
代码测试:
int main() { string str1 = "abcdefgh"; string str2 = str1; rotate1(str1, 4); rotate2(str2, 4); for(auto it : str1) cout << it; cout << endl; for(auto it : str2) cout << it; cout << endl; return 0; }
“块交换”法:
void swap(char &a, char &b) { char tmp = a; a = b; b = tmp; } void exchange(string &str, int first, int last, int i) { for(int num = 0; num < i; ++num) swap(str[first+num], str[last-i+num+1]); } void move(string &str, int &first, int &last, int &num) { if(last-first+1 > num) //判断要旋转的量和当前块长度的关系,若旋转量已经等于块长度,则旋转已经完成 { int len = last - first + 1 - num; //假设分成ab两块,交换成ba,len表示块b的长度 int numOfSwap = num <= len ? num : len; //确定要交换的量 exchange(str, first, last, numOfSwap); if(num <= len) last -= num; //新块的索引已经改变 else { first += len; num -= len; } move(str, first, last, num); } } void rotate(string &str, int num) { int first = 0; int last = str.size() - 1; move(str, first, last, num); }