字符串全排列算法學習


最近做了一道阿里的筆試題

1.  字符串“alibaba”有     個不同的排列。

A. 5040            B. 840               C. 14               D.420

用概率的辦法可以直接求解出C73*C42*A22,C73,7是下標,3是上標,結果是420;

 

后來查了一下,這是一個全排列的問題,於是學習了一下全排列的算法。

學習的博客http://blog.csdn.net/wzy_1988/article/details/8939140

問題

輸入一個字符串,打印出該字符串中字符的所有排列。例如輸入字符串abc,則輸出由字符a,b,c所能排列出來的所有字符串abc,acb,bac,bca,cab和cba
 
正常人的思維是,固定第一個字符,然后依次將后面的字符串與前面的交換,那么排列的個數就是除了第一個字符以外,其他字符的排列個數+1。
 
也就是固定一個字符串之后,之后再將問題變小,只需求出后面子串的排列個數就可以得出結果,當然第一時間想到的就是遞歸的算法了。
 
下面這張圖很清楚的給出了遞歸的過程:

很明顯,遞歸的出口,就是只剩一個字符的時候,遞歸的循環過程,就是從每個子串的第二個字符開始依次與第一個字符交換,然后繼續處理子串。
 
還有一個問題要注意,就是如果字符串中有重復的字符串
 
由於全排列就是從第一個數字起,每個數分別與它后面的數字交換,我們先嘗試加個這樣的判斷——如果一個數與后面的數字相同那么這兩個數就不交換 了。例如abb,第一個數與后面兩個數交換得bab,bba。然后abb中第二個數和第三個數相同,就不用交換了。但是對bab,第二個數和第三個數不 同,則需要交換,得到bba。由於這里的bba和開始第一個數與第三個數交換的結果相同了,因此這個方法不行。

換種思維,對abb,第一個數a與第二個數b交換得到bab,然后考慮第一個數與第三個數交換,此時由於第三個數等於第二個數,所以第一個數就不再用與第三個數交換了。再考慮bab,它的第二個數與第三個數交換可以解決bba。此時全排列生成完畢!

這樣,我們得到在全排列中去掉重復的規則:
去重的全排列就是從第一個數字起,每個數分別與它后面非重復出現的數字交換。
 
所以代碼如下
 1 #include <stdio.h>
 2 
 3 static int count = 0;
 4 
 5 void swap(char* str,int a,int b)
 6 {
 7     char tmp = str[a];
 8     str[a] = str[b];
 9     str[b] = tmp;
10 }
11 
12 
13 int is_swap(char *str, int begin, int k){   //判斷從子串的第一個字符串開始,直到k-1位置,看是否有重復的字符
14     int i, flag;
15 
16     for (i = begin, flag = 1; i < k; i ++) {
17         if (str[i] == str[k]) {
18             flag = 0;
19             break;
20         }
21     }
22 
23     return flag;
24 }
25 
26 void full_permutation(char* str,int begin,int end)
27 {
28     if (begin == end)
29     {
30         count++;//此處可以輸出字符串或者記錄字符串
31         return;
32     }else{
33         int i;
34         for (i = begin; i <= end; i++)
35         {
36             if (is_swap(str,begin,i))
37             {
38                 swap(str,begin,i);
39                 full_permutation(str,begin+1,end);
40                 swap(str,begin,i);
41             }
42         }
43     }
44 }
45 
46 int main()
47 {
48     char str[7] = {'a','l','i','b','a','b','a'};
49     full_permutation(str,0,6);
50     printf("count=%d",count);
51     return 0;
52 }

運行結果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM