描述:
给定一个字符串,要求把字符串前面若干个字符移位到字符串的尾部。
思路与代码:
1 //暴力法 2 #include<stdio.h> 3 #include<string.h> 4 5 const int MAXN = 1e5; 6 void move_one(char *s, int n) //移动一个字符到尾部 7 { 8 char t = s[0]; //保存第一个字符 9 for(int i = 1; i < n; i++) 10 { 11 s[i - 1] = s[i]; 12 } 13 s[n - 1] = t; 14 } 15 void move(char *s, int n, int m) //移动前m个字符到尾部 16 { 17 while(m--) 18 { 19 move_one(s, n); 20 } 21 } 22 int main() 23 { 24 char str[MAXN]; 25 int m; 26 while(scanf("%s", str) != EOF) 27 { 28 getchar(); 29 scanf("%d", &m); 30 int len = strlen(str); 31 move(str, len, m); 32 for(int i = 0; i < len; i++) 33 printf("%c", str[i]); 34 printf("\n"); 35 } 36 return 0; 37 }
暴力法的复杂度:
对一个长度为n的字符串来说,若需要移动m个字符到尾部,时间复杂度为O(m*n),空间复杂度为O(1),接下来来找找其他更好的方法来降低时间复杂度。
举个例子,对于一个字符串abcdef,要将前三个移到尾部,可以先将原字符串划分成两部分,分别为字符串X:abc和字符串Y:def,然后将X反转变为cba,将Y反转变为fed,再将反转后的两字符串连接成cbafed,最后将连接后的再次反转即为defabc,得到移位后的字符串。所以找到了一种更高效的算法,将原字符串分成X和Y两部分,定义X^T为将字符串反转操作,则有(X^TY^T)^T=YX。
1 //三步反转法 2 #include<stdio.h> 3 #include<string.h> 4 5 const int MAXN = 1e5; 6 void reverse(char *s, int left, int right) //反转字符串 7 { 8 while(left < right) 9 { 10 char t = s[left]; 11 s[left++] = s[right]; 12 s[right--] = t; 13 } 14 } 15 void move(char *s, int n, int m) 16 { 17 m %= n; //若移动个数大于原长度,则和取余结果相等 18 reverse(s, 0, m - 1); //前部分[0,...,m-1] 19 reverse(s, m, n - 1); //后部分[m,...,n-1] 20 reverse(s, 0, n - 1); //再整体反转 21 } 22 int main() 23 { 24 char str[MAXN]; 25 int m; 26 while(scanf("%s", str) != EOF) 27 { 28 getchar(); 29 scanf("%d", &m); 30 int len = strlen(str); 31 move(str, len, m); 32 for(int i = 0; i < len; i++) 33 printf("%c", str[i]); 34 printf("\n"); 35 } 36 return 0; 37 }
三步反转法的复杂度:
时间复杂度O(n),空间复杂度O(1)