2014阿里巴巴 實習生電面題目:輸出給定字符串的全部連續子串

轉載請註明出處:http://blog.csdn.net/ns_code/article/details/21043665

    今天下午阿里電面的題目,給定一個字符串,輸出其所有連續子串,如:給定字符串爲abcd,則要輸出的其全部連續子串爲:a,b,c,d,ab,bc,cd,abc,bcd,abcd。

    很快給出了最簡單的方法,就是先從第一個字符遍歷,向後輸出,再從第二個字符開始遍歷,向後輸出,依此類推,直到開始遍歷的字符爲數組的最後一個字符。這個時間複雜度很高啊,要O(n*n*n)。

    接下來就假設字符串很大,想優化的方法,不知道腦子是短路了還是咋地,居然聯想到Trie樹上去了,完全不沾邊的東西。電面後想了下,感覺應該用遞歸,吃完飯,去圖書館用紙畫了下,就是遞歸(還是A題A的少啊!)。後來寫出來代碼感覺貌似木有提高時間複雜度哦!

    先貼出來吧,首先是最簡單的遍歷法,時間複雜度爲O(n*n*n)

[cpp] view plaincopy

  1. /*
  2. 蠻力求解法
  3. */
  4. void AllSubstring1(const char *str,int high)  
  5. {  
  6. int i, j, k;  
  7. if(!str)  
  8. return;  
  9. for(i=0;i<=high;i++)  
  10. {  
  11. for(j=i; j<=high;j++)  
  12.     {  
  13. for(k = i; k<=j; k++)  
  14.             printf("%c", str[k]);  
  15.         printf("\t");  
  16.     }   
  17.     printf("\n");  
  18.     }  
  19. }  

    而後我又減少了一層循環,增加了一個遞歸操作,如下:

[cpp] view plaincopy

  1. /*
  2. 遞歸求解法
  3. */
  4. void AllSubstring2(const char *str,int low,int high)  
  5. {  
  6. int i;  
  7. int cur = high;  
  8. if(!str)  
  9. return;  
  10. while(low <= cur)  
  11.     {  
  12. for(i=low;i<=cur;i++)  
  13.             printf("%c",str[i]);  
  14.         printf("\t");  
  15.         cur--;  
  16.     }  
  17.     printf("\n");  
  18. if(low<high)  
  19.     {  
  20.         AllSubstring2(str,low+1,high);  
  21.     }  
  22. }  

    但是感覺時間複雜度沒有提高啊(分治策略的遞歸代替循環,可以將時間複雜度從O(n)降到O(logn),當然是每次將問題減到一半分治策略,若果是類似斐波那契序列的分治,效果更差。每層遞歸只減少一個元素的遞歸無法降低時間複雜度)!我在紙上大致算了下。遞歸求解的時間複雜度按如下公式推導:

T(n) = T(n-1) + n*n

    這樣應該得到:

T(n) = n*n + (n-1)*(n-1) +...+2*2 + 1 = n(n+1)(2n+1)/6

    時間複雜度還是O(n*n*n)!!

    而且感覺還可以用一個遞歸來替代上面的一層循環,沒時間想了,圖書館要關門了,還要去跑步,明天又要跟導師彙報,暫時先擱一擱吧!忙完了再回來思考下,大家有好的思路的話,希望在下面貼出來!

後續

    沒想到發生來一天不到,那麼多人回覆,很感謝大家的熱心思考啊!而且看時間有些人是熬夜寫的代碼啊,不由心生佩服,不過希望要多注意身體哈。

    很多人都採用瞭如下代碼來進行優化(我稍微做了些改動,測試通過)

[cpp] view plaincopy

  1. /*
  2. 循環輸出子串
  3. */
  4. void AllSubstring3(const char *str,char *arr)  
  5. {  
  6. //穿入的arr的長度爲len+1,最後一個位置保存'\0'
  7. int i,j;  
  8.     unsigned int len = strlen(str);  
  9.     strcpy(arr,str);  
  10. for(i=len-1;i>=0;i--)  
  11.     {  
  12.         arr[i+1] = '\0';  
  13. for(j=i;j>=0;j--)  
  14.             printf("%s\t",&arr[j]);  
  15.         printf("\n");  
  16.     }  
  17. }  

    採用直接打印子串的方法,減少了一個循環,18樓說的在理,這樣只是代碼間簡潔了些,但直接輸出字符串和諸葛輸出字符效果是一樣的,因此複雜度並沒有降低。

    假設沒有重複的情況,連續子串的數目爲sum = n + n-1 + n-2 +...+2+1 = n(n-1)/2,但是因爲基本的操作是輸出單個字符,因此輸出次數也就達到了sum*n的級別了,時間複雜度最優貌似也就是O(n*n*n)了,這樣看來貌似就沒什麼可優化的餘地嘍!!求解。。

    再次感謝大家的思考和回覆,最近忙死鳥,不能一一細看和回覆,望見諒!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章