CVTE筆試題---字串的全排列
今天筆了cvte的實習生線上筆試題,一個感覺,基礎很重要,如果沒有紮實的基礎,全是不定項的選擇題,真的都是致命傷;
下面我就程式設計題–字串的全排列進行總結;
當然,這道題在劍指offer上就有,面試經常出,我以前也做過,但是時間長了,不太熟了,做的時候挺吃力,就在這裡總結一下吧!
題目: 輸入一個字串,列印該字串中字元的所有排列,例如輸入abc,則打印出abc,acb,bac,bca,cab,cba。
解法一:遞迴
就是常見的遞迴的解法,先固定第一個位置的字元,然後排列後面的字元,然後和第二個字元交換,將第二個字元固定在第一個位置,排列後面的字元,依次類推,就排列出了所有組合,其實就是個遞迴的問題,大問題不停的劃分為子問題;
abc為例:
1> 固定a,對bc進行排列,我們又可以把bc當做一個子問題,固定b,對c進行排列,c已經不能再分了,那就打印出abc;
2>又回到了b,b和下一個位置進行交換,即變為cb,在bc這個子問題中,該讓c變為第一個字元了,遞迴得到acb;
2>又回到了b,但是此時是c為第一個,所以我們需要,將b和c的位置換回去,因為當退回到a的時候,或者c後面還有d的時候,我們需要d固定到b的位置,bc進行排列,如果不換回bc的位置,那麼不會得到預期的結果,返回a時也一樣,如果不把bc換回bc那麼回到a之後,替換第一個位置的字元就變為了 c,此時字串是cab, 那麼又對ab進行排列,最後變為ba, 如果不換回位置的話,等返回到c的時候就變為了 cba, 那麼此時該把第三個字串固定到第一個位置了,豈不是又變成了abc?
所以,每次交換位置進行遞迴之後,需要還原位置;
文字描述比較抽象一點,需要自己進行在本子上一步步的推理,才能理解;
主要程式碼邏輯如下:
void printR(char* str,int start, int len)
{
if(start == len - 1)
{
//到達字串最後
printf("%s , " ,str);
}
else
{
for(int i = start; i < len - 1; i++)
{
//讓後面的字元依次固定在第一個位置
swap(str[start],str[i]);
printfR(str ,start+1,len);
swap(str[start],str[i]);
//最後恢復str的原樣;
}
}
}
void Print(char* str)
{
if(str == NULL)
return;
printfR(str,0,strlen(str)); //遞迴函式
}
–解法二:
熟悉STL的話,你可以在STL裡找到一個next_permutation 函式;
如果你輸入一段字串(注意,引數其實是迭代器),那麼它會按返回這個字串的下一個組合,但是必須是有序的,所以使用之前我們得排一次序,也就說明了使用的限制。具體解釋看STL原始碼剖析P380;
使用如下:
void Print(char *str)
{
int len = strlen(str);
sort(str,str+len);
do{
printf("%s ,",str);
}while(next_permutation(str,str+len));
}