字符串循环移位问题是面试中比较容易遇到的,就是输入一个字符串和一个整数,原地输出移位后的字符串。
不同的考官可能对程序的具体要求不同,这里要求空间复杂度为O(1)。
这里给出两种解答方法。
(1)将移动n位看做“每次移动一位,共操作n次”,这是一种化整为零的思维方法。只要能想到这一步,相信下面的代码就不难写出了:
1 void shift_1(char* str) 2 { 3 int len = strlen(str); 4 if(len <= 1) 5 return; 6 char temp = str[len-1]; 7 for(int i=len-1; i>= 1; i--) 8 str[i] = str[i-1]; 9 str[0] = temp; 10 } 11 void shift_n(char* str, int n) 12 { 13 if(! str) 14 return; 15 for(int i=1; i<= n; i++) 16 shift_1(str); 17 }
很显然这个算法的时间复杂度为O(nl), 空间复杂度为O(1)。其中l为字符串长度。
(2)观察移位后的字符串和原串的差别,字符串移n位相当于把前n位挪到了后面,而把后n位移到前面。
设字符串长为L,把字符串分成2个部分,前(L-n)个字符看做子串A,后n个字符看做子串B,则字符串可用AB表示。完成移位操作后新串为BA。
那么移位的过程就可以看做AB到BA的过程。
用A’表示A的反序串,B’表示B的反序串,那么 BA = B”A” =(A’B’)’。 代码如下:
1 // 将一个字符串中某个子串反序 2 void reverseOrder(char* str, int p, int q) 3 { 4 char temp; 5 while(p < q) 6 { 7 temp = str[p]; 8 str[p] = str[q]; 9 str[q] = temp; 10 p ++; 11 q --; 12 } 13 } 14 void shift_n(char* str, int n) 15 { 16 if( !str) 17 return; 18 int len = strlen(str); 19 int t = n % len; 20 reverseOrder(str, 0, len - t -1); 21 reverseOrder(str, len - t, len -1); 22 reverseOrder(str, 0, len -1); 23 }
算法的空间复杂度为O(1)。把赋值操作作为考量时间复杂度的基本单位,3次调用reverseOrder函数总共执行赋值操作3l,则算法的时间复杂度为O(l)。