字符串的排列和組合問題


1、字符串的全排列

題目:{a,b,c}要求輸出{abc,acb,bac,bca,cab,cba}。

字符串全排列可以把字符串看成兩個部分,第一個部分為它的一個字符,第二部分是后面的字符。

分兩步完成:首先求所有可能出現在第一個位置的字符,即把第一個字符與后面的所有字符交換。第二步固定第一個字符,求后面所有字符的排列。從中可以看出是典型的遞歸思路。 

 1     public void helper(char[] array, int cur){
 2         if ( cur == array.length - 1 ) print(array);
 3         else {
 4             for ( int i = cur ; i < array.length ; i ++ ){
 5                 swap(array,cur,i);
 6                 helper(array,cur+1);  //固定第一個字符,對后面所有字符全排列
 7                 swap(array,i,cur);
 8             }
 9         }
10     }

如果給的字符中出現重復,即{a,b,c,c}這種情況,可以判斷當前准備交換的字符,如果當前准備交換的字符已經在cur前面的字符中出現過了,就跳過,否則就交換。修改后方法如下:

 1     public void helper(char[] array, int cur){
 2         if ( cur == array.length - 1 ) print(array);
 3         else {
 4             for ( int i = cur ; i < array.length ; i ++ ) {
 5                 if (!isExit(array, cur, i)) {
 6                     swap(array, cur, i);
 7                     helper(array, cur + 1);  //固定第一個字符,對后面所有字符全排列
 8                     swap(array, i, cur);
 9                 }
10             }
11         }
12     }
13     private boolean isExit(char[] array, int cur, int i) {
14         for ( int k = cur ; k < i ; k ++ ){
15             if ( array[k] == array[i] ) return true;
16         }
17         return false
18     }

 

2、字符串組合

題目:{a,b,c}要求輸出{a,b,c,ab,ac,bc,abc}。

分析,可以將題目分成小問題來理解,1個字符的組合+2個字符的組合+3個字符的組合,因此我們只要找到一般的方法,即從n個字符中找m個字符的組合就可以了。

我們可以把n個字符分成兩部分,第一個字符和其他所有字符。如果組合里包含第一個字符,則下一步在剩余的字符里選取m-1個字符;如果組合里不包含第一個字符,則下一步在剩余的n-1個字符里選取m個字符,從中可以看出又是個遞歸的過程。

 1     Stack<Character> stack = new Stack<>();
 2     public void helper(char[] array){
 3         for ( int i = 1 ; i <= array.length ; i ++ )
 4             combination(array,0,i);
 5     }
 6     private void combination(char[] strArr, int begin, int num) {
 7         if (num == 0) {
 8             System.out.println(stack);
 9             return;
10         }
11         if (begin >= strArr.length) {
12             return;
13         } else {
14             //把第一個字符放入組合中,在剩余的字符中選取num-1個字符
15             stack.push(strArr[begin]);
16             combination(strArr, begin + 1, num - 1);
17             //組合里不包含第一個字符,則下一步在剩余的字符中選取num個字符
18             stack.pop();
19             combination(strArr, begin + 1, num);
20         }
21     }

helper函數表示求長度為i的全排列。

還有一種更nb的方法,因為組合問題,比如3個元素的組合就有2^3-1種,所以不妨給他們進行編號,就像上面的問題,從a——abc一次編號為 001——111。1就代表該位置出現字符。例如:001->c,010->b,101->ac......,所以原題就是要求輸出"001"-"111"這2^n-1個組合對應的字符串。

 1 public static void main(String[] args) {
 2 
 3   String s = "abc";
 4   ArrayList<String> result = combineString(s);
 5   for(String r : result){
 6     System.out.println(r);
 7   }
 8 }
 9 
10 private static ArrayList<String> combineString(String s) {
11   int len = s.length();
12   ArrayList<String> list = new ArrayList<String>(); 
13   int count = (int) (Math.pow(2, len));
14   for(int i = 1; i < count; ++i){
15     String temp = "";
16     String str = Integer.toBinaryString(i);
17     while(str.length() < len){
18       str = "0" + str;
19     }
20     for(int j = 0; j < str.length(); ++j){
21       if(str.charAt(j) == '1'){
22         temp += s.charAt(j);
23       }
24     }
25     list.add(temp);
26   }
27   return list;
28 }


免責聲明!

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



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