求出所有排列 去重全排列 回溯算法


一、"alibaba"這個字符串有多少種排序方法

二、去重全排列

方法1:去重的全排列就是從第一個數字起,每個數分別與它后面非重復出現的數字交換(重復數據第一個交換之后不交換)

(1)第一個字符a與后面的字符交換得到abcc(不交換)、bacc(和b交換)、cabc(和c交換),因為第四位的c和第三位相同,所以a和第四位不交換。

(2)以此類推,直到最后一個字符。

(3)代碼

import java.util.ArrayList;
import java.util.Collections;
import java.util.Set;
import java.util.HashSet;
public class Solution {
    public ArrayList<String> Permutation(String str) {
        ArrayList<String> list = new ArrayList<String>();
        if(str != null && str.length()>0){
            PermutationHelper(str.toCharArray(), 0, list);//整個字符串排序
           // Collections.sort(list);
            Collections.sort(list);//對list中數據進行字典排序
        }
        return list;
    }
    
    public void PermutationHelper(char[] chars, int i, ArrayList<String> list){
        if(i == chars.length-1){
            list.add(String.valueOf(chars));
        }else{
            Set<Character> charSet = new HashSet<Character>();
            for(int j = i; j<chars.length; j++){
                if(j==i || !charSet.contains(chars[j])){
                    charSet.add(chars[j]);
                    swap(chars,i,j);//交換得到chars
                    PermutationHelper(chars,i+1,list);//固定前i個元素之后的字符串排序結果chars
                    swap(chars,j,i);//交換回來
                }
                
            }
        }
    }
    public void swap(char[] chars,int i,int j){
        char temp = chars[i];
        chars[i] = chars[j];
        chars[j] = temp;
    }
        
}

方法2:回溯法

1.回溯法定義:

回溯法(探索與回溯法)是一種選優搜索法,又稱為試探法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,而滿足回溯條件的某個狀態的點稱為“回溯點”。

2.參考

https://blog.csdn.net/versencoder/article/details/52071930

https://blog.csdn.net/versencoder/article/details/52072350

 3.解題思路

問題:給兩個整數 n和k,從1---n中選擇k數字的組合。比如n=4,k=2,那么從1,2,3,4中選取兩個數字的組合,包括如下所述的四種。

[

 [2,4],

 [3,4],

 [2,3],

 [1,2],

 [1,3],

 [1,4],

]

題目所給框架:

public class Solution {

   public List<List<Integer>> combine(int n, int k) {

       

    }

}

(1)要求返回的類型是List<List<Integer>> 也就是說將所有可能的組合list(由整數構成)放入另一個list(由list構成)中。要求返回List<List<Integer>>,那么 定義一個全局變量

List<List<Integer>> result=new ArrayList<List<Integer>>();

(2)定義一個輔助的方法(函數),其中n,k是題目要求的變量,List<Integer>list是數字的組合,也是需要的。

public void backtracking(int n,int k, List<Integer>list){}

(3)如何實現這個算法?對於n=4,k=2,1,2,3,4中選2個數字,我們可以做如下嘗試,加入先選擇1,注意這時候k=1了(此時只需要選擇1個數字),那我們只需要從(2----4)中再選擇一個數字(調用backtracking())。每次選擇一個加入我們的鏈表list中,此時找到[1,2],[1,3],[1,4]。之后選擇2作為第一個數字,在從(3---4)中查找剩余的一個,以此類推。那什么時候結束呢?當然是k<0的時候,這時候都選完了。

publicvoid backtracking(int n,int k,int start,List<Integer> list){
        if(k<0)        return;
        else if(k==0){
                       //k==0表示已經找到了k個數字的組合,這時候加入全局result中
            result.add(new ArrayList(list));
 
        }else{
            for(int i=start;i<=n;i++){//start表示開始的位置,開始點加入list中,再從開始點之后查找剩余數字
                list.add(i);//嘗試性的加入i
                    //開始回溯啦,下一次要找的數字減少一個所以用k-1,i+1見后面分析
                backtracking(n,k-1,i+1,list);
                //(留白,有用=。=)
            }
        }
    }

(4)在循環中調用backtracking(n,k-1,i+1,list);時,list在之后已經又加入了一個數字,所以要回退一個數字,之后在查找。例如backtracking(4,2,1,null),在for循環中,list.add(1),之后調用backtracking(4,1,2,[1]),在調用backtracking(4,1,2,[1])中開啟第一次循環返回[1,2],第二次循環若沒有回退,則會在原有[1,2]基礎上list.add(3),。所以回退應該在留白處回退到初始地方,再向下繼續查找。所以完整的程序如下:

public class Solution {
   List<List<Integer>> result=new ArrayList<List<Integer>>();
   public List<List<Integer>> combine(int n, int k) {
       List<Integer> list=new ArrayList<Integer>();
       backtracking(n,k,1,list);
       return result;
    }
   public void backtracking(int n,int k,int start,List<Integer>list){
       if(k<0) return ;
       else if(k==0){
           result.add(new ArrayList(list));
       }else{
           for(int i=start;i<=n;i++){
                list.add(i);
                backtracking(n,k-1,i+1,list);
                list.remove(list.size()-1);
            }
       }
    }
}

 

 


免責聲明!

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



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