题目要求:
定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部。
例如:把字符串abcdef左旋转2位得到字符串cdefab。请实现字符串左旋转函数。
参考资料:剑指offer第42题、编程珠玑第二章
题目分析:
方法1 临时空间法:将前i个元素先复制到临时空间中,然后将余下的n-i个元素前移i个位置,最后再把临时空间中的元素放到余下的位置。【分析:如果前i个元素数据量很大,那么临时空间将会很消耗。】
方法2 逐步旋转法:定义一个函数(其功能是将整个向量左旋1位),然后重复调用这个函数i次。【分析:这样会很耗时。】
方法3 杂技法:把a[0]放入一个临时元素中,然后把a[i]放到a[0],a[2i]放到a[i],以此类推(前提是ki < n。如果ki > n,则ki对n取余,如果余数不等于a[0],则继续循环,否则结束本次循环);然后把a[1]放到一个临时元素中,进行和a[0]一样的操作;然后...a[m]。其中m的大小是i和n的最大公倍数。
方法4 块变换法:我们将需要旋转的向量x看成是由向量a和b组成的,那么旋转向量x实际上就是将向量ab的两个部分交换为向量ba,这里向量a代表x的前i个元素。那么整体的变换步骤就可以总结如下了(假设a比b短):
1)将b分割为bl和br两个部分,使得br的长度和a的长度一样(等于i)
2)交换a和br,即ablbr转换成了brbla。通过本次变换,序列a就位于它的最终位置了。
3)我们需要集中精力交换b的两个部分了,这个时候就回到了最初的问题上了。
方法5 翻手算法:时间、空间复杂度和代码简单程度综合性价比最高的算法。
代码实现:
杂技法:
#include <stdio.h> int Gcd(int n,int i); void Sort(int a[],int rotate,int len,int gcd); int main(void) { int a[5]={1,2,3,4,5}; int gcd; gcd = Gcd(5,4); Sort(a,4,5,gcd); for(gcd=0; gcd < 5;gcd++) { printf("%d",a[gcd]); } printf(" "); return 0; } int Gcd(int n,int i) { while(i != n) { if(i > n) { i -= n; } else { n -= i; } } return i; } void Sort(int a[],int rotate,int len,int gcd) { int i,temp,next,before; for (i = 0; i < gcd; i++) { temp = a[i]; before = i; while (1) { next = (before + rotate) % len; if (next == i) { break; } else { a[before] = a[next]; before = next; } } a[before] = temp; } }
块变换法:
#include <stdio.h> #define MAX 10 char x[MAX] = "abcdefgh"; /* * aStart : The start index of block a. bStart : The start index of block b. length : The size to be swapped. */ void swap(int aStart, int bStart, int length) { char tmp; while(length-- > 0) { tmp = x[aStart]; x[aStart] = x[bStart]; x[bStart] = tmp; aStart++; bStart++; } } void rotate(int rotdist, int n) { int i,j; int p; /* check rotdist */ if (rotdist == 0 || rotdist == n) { return; } /* split the array to two block */ i = p = rotdist; j = n - rotdist; while (i != j) { if (i > j) { /* The start of block b never changed */ swap(p - i, p, j); i -= j; } else { swap(p - i, p+j-i,i); j -=i; } } /* i == j */ swap(p-i,p,i); } int main() { rotate(4,8); printf("%s",x); return 0; }
翻手算法:
#include <stdio.h> void reverse(int a[],int start,int end); void TurnHands(int a[],int i,int n); int main(void) { int a[9]={1,2,3,4,5,6,7,8,9}; int i; TurnHands(a,5,9); for(i = 0;i < 9;i++) { printf("%d",a[i]); } printf(" "); return 0; } void reverse(int a[],int start,int end) { if(a==NULL) return; int i=start,j=end,temp; for(;i < j;i++,j--) { temp=a[i]; a[i]=a[j]; a[j]=temp; } } void TurnHands(int a[],int i,int n) { if(a==NULL) return; if(i<=0 || n<=0 || i>n) return; reverse(a,0,i-1); reverse(a,i,n-1); reverse(a,0,n-1); }