1. 程式人生 > 程式設計 >leetcode46.全排列

leetcode46.全排列

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

示例:

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

來源:力扣(LeetCode) 連結:leetcode-cn.com/problems/pe… 著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。

兩種解法,一種回溯,一種字典序。

回溯:比較簡單,直接上程式碼

public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        //回溯法
        //per(0,nums,result);
        return
result; } //回溯 private void per(int cur,int[] nums,List<List<Integer>> result){ //cur指標走到陣列最後,記錄值,並返回 if(cur == nums.length-1){ add(nums,result); return; } //固定一位後,遞迴交換下一位 for(int i = cur;i<nums.length;i++){ //交換 swap(cur,i,nums); //遞迴 per(cur+1,result); //回溯 swap(cur,nums); } } private void add(int[] nums,List<List<Integer>> result){ List<Integer> list = new ArrayList<>(); for
(int i = 0;i<nums.length;i++){ list.add(nums[i]); } result.add(list); } //對換 private void swap(int i,int j,int[] nums){ int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } 複製程式碼

字典序:

通過字典序演演算法來獲得下一個字典序,但需要先從小到大排序。

字典序演演算法:

(1)從右向左找到第一個下標為i,其中nums[i]<nums[i+1],記錄i

(2)從右向左找到第一個比i大的數,下標為j,交換i,j,

(3)此時i+1之後的數字為從大到小排列,翻轉i+1至陣列末尾的資料,得到下一個排列。

 public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        //字典序演演算法
        Arrays.sort(nums);
        add(nums,result);
        while(getNextDictionaryPreface(nums)){
           add(nums,result);
        }
        return result;
    }
    private void add(int[] nums,List<List<Integer>> result){
        List<Integer> list = new ArrayList<>();
        for(int i = 0;i<nums.length;i++){
            list.add(nums[i]);
        }
        result.add(list);
    }
    //對換
    private void swap(int i,int[] nums){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
    //得到下一個字典序
    private boolean getNextDictionaryPreface(int[] nums){
        //如果長度為1,則沒有下一個字典序
        if(nums.length<=1 || nums == null) return false;
        //從右到左找到第一個左邊小於右邊的數,並記錄
        int jiluleft = -1;
        for (int i = nums.length-2; i>=0 ;i--){
            if(nums[i] < nums[i+1]){
                jiluleft = i;
                break;
            }
        }
        //若jiluleft值不變,說明沒有下一個字典序,例如{4,1}
        if(jiluleft == -1)
            return false;
        else{
            //從右到左找到第一個大於nums[jiluleft]的數,並交換

            for (int i = nums.length-1; i>=jiluleft ;i--){
                if(nums[i] > nums[jiluleft]){
                    swap(jiluleft,nums);
                    break;
                }
            }
            //翻轉left+1至陣列末尾
            reversalNums(jiluleft+1,nums.length-1,nums);
            return true;
        }
    }
    //翻轉陣列
    private void reversalNums(int left,int right,int[] nums){
        while(right > left){
            swap(left,right,nums);
            left++;right--;
        }
    }
複製程式碼