书中讲到三种方法,“杂技”交换、“求逆算法”和“块交换”法,注意形参一定要传引用!
“杂技”交换法:
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);
}