全排列問題


在解決全排列問題之前,先講解一個它的子問題,輸出給定數字比它大的下一個數字,為了方便,我們把輸入和輸出數字用數組表示

給出一組數,輸出它的下一個排列

假設給定數組[1,2,3,5,4]  比它大的下一個數字是[1,2,4,3,5]

思想:

假設出入數組為arr

1.我們從后向前遍歷,找到arr[i]>arr[i-1],並且返回i,如果沒有找到返回0;

2.用index接收返回的下標,判斷index是否等於0,如果等於0,返回null,否則在區間 arr.length-1 和 index 區間找出比arr[index-1]小的值,兩者交換,並退出循環;

3.在對 index和arr.length-1組成的區間 進行逆序,

4.返回數組arr,數組arr表示當前數組的下一個排列

實現圖如下:

實現代碼如下:

     //找到下一個排列 
     public static int[] findNearestNumber(int[] arr){ int index = returnIndex(arr); if(index == 0) return null; for(int i = arr.length-1;i>=index;i--){ if(arr[index-1]<arr[i]){ int tmp = arr[index-1]; arr[index-1] = arr[i]; arr[i] = tmp; break; } } reverseArr(arr,index,arr.length-1); return arr; } //逆序
    public static void reverseArr(int[] arr,int start,int end){ while(start<=end){ int tmp = arr[start]; arr[start++] = arr[end]; arr[end--] = tmp; } } //從后向前遍歷找出arr[i]<arr[i-1]的下標i
    public static int returnIndex(int[] arr){ for (int i = arr.length-1; i >0 ; i--) { if(arr[i]>arr[i-1]){ return i; } } return 0; }

這就是求一個數組的下一個排列數組,是不是很簡單?

 

下面這個全排列的例子該如何實現呢?

給定一個沒有重復數字的序列,返回其所有可能的全排列。

示例:

輸入: [1,2,3]
輸出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

通過上面的例子,我們可以求出一個數組的比它大的下一個數組,那么我們要輸出給定某數組的全部排列就很簡單了,在解決此題之前,我們首先的判斷該數組總共有多少排列組合,然后在進行操作,先對該數組按升序進行排序,也就是最小值a,我們可以求a的下一個排列b,緊接着我們可以求b的下一個排列c...直到該排列為空,我們就求出了該數組的全部排列組合。

代碼如下:

public List<List<Integer>> permute(int[] nums) { Arrays.sort(nums); int length = nums.length; List<List<Integer>> list = new ArrayList<List<Integer>>(); int n = getN(length); for(int i = 0;i<n;i++){ List<Integer> list1 = new ArrayList<Integer>();
//將原數組加入集合中
if(i == 0){ List<Integer> list2 = new ArrayList<Integer>(); for(int j:nums){ list2.add(j); } list.add(list2); }
       //求得nums下一個排列 nums
= findNearestNumber(nums);
        //如果返回數組為null表示已經排列完成,結束循環
if(nums == null) break;
//將數組元素加入集合中
for(int j:nums){ list1.add(j); }
   //將集合list1加入集合list中 list.add(list1); }
return list; } //獲取總共的排列組合數 public static int getN(int length){ if(length == 1){ return length; } return length*getN(length-1); } //排列 public static int[] findNearestNumber(int[] arr){ int index = returnIndex(arr); if(index == 0) return null; for(int i = arr.length-1;i>=index;i--){ if(arr[index-1]<arr[i]){ int tmp = arr[index-1]; arr[index-1] = arr[i]; arr[i] = tmp; break; } } reverseArr(arr,index,arr.length-1); return arr; } //逆序 public static void reverseArr(int[] arr,int start,int end){ while(start<=end){ int tmp = arr[start]; arr[start++] = arr[end]; arr[end--] = tmp; } } //從后向前遍歷找出arr[i]<arr[i-1]的下標i public static int returnIndex(int[] arr){ for (int i = arr.length-1; i >0 ; i--) { if(arr[i]>arr[i-1]){ return i; } } return 0; }

如果給定的數組有重復的數字,那么我們該如何解決呢?

其實上面的代碼也適用於數組有重復數字,這就是采用非遞歸的好處。

下面是采用遞歸實現代碼:

這個代碼實現給定的數組中沒有重復數字的

   //遞歸實現 調用時n是0
    public static void printSort(int[] num, int n) {
        if(n >= num.length-1){
            System.out.println(Arrays.toString(num));
        }
        else{
            for(int i = n;i < num.length;i++) {
                    swap(num,i,n);
                    printSort(num,n+1);
                    swap(num,i,n);
 
            }
        }
    }
   //交換指定下標元素
    public static void swap(int[] num, int i, int n) {
        int flag = num[i];
        num[i] = num[n];
        num[n] = flag;
    }
 

如果有重復的元素,用遞歸該如何實現,其實很簡單,我們只要讓第一次出現該數作為開頭

代碼如下:

 //調用時n是0
    public static void printSort(int[] num, int n) {
        List<Integer> list = new ArrayList<Integer>();
        if(n >= num.length-1){
            System.out.println(Arrays.toString(num));
        }
        else{
            for(int i = n;i < num.length;i++) {
                //篩選重復的數
                if(!list.contains(num[i])){
                    list.add(num[i]);
                    swap(num,i,n);
                    printSort(num,n+1);
                    swap(num,i,n);
                 }
            }
        }
    }
 
    public static void swap(int[] num, int i, int n) {
        int flag = num[i];
        num[i] = num[n];
        num[n] = flag;
    }
 

  


免責聲明!

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



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