1. 程式人生 > 其它 >LeetCode-47. 全排列 II

LeetCode-47. 全排列 II

題目來源

47. 全排列 II

題目詳情

給定一個可包含重複數字的序列 nums按任意順序 返回所有不重複的全排列。

示例 1:

輸入: nums = [1,1,2]
輸出:
[[1,1,2],
[1,2,1],
[2,1,1]]

示例 2:

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

提示:

  • 1 <= nums.length <= 8
  • -10 <= nums[i] <= 10

相似題目

LeetCode-78. 子集
LeetCode-46. 全排列
LeetCode-47. 全排列 II

題解詳情

解法一:回溯

本題與[LeetCode-46. 全排列]和[LeetCode-78. 子集]這兩道題目都十分相似,主要是遞迴和回溯演算法的考察。

與全排列題目相比,這道題目增加的一個難度就是將無重複元素改成了有重複元素,這就使得我們無法使用全排列這道題目的解題思路來解決問題了。但是,我們需要知道的,我們都需要使用回溯來列舉到所有滿足條件的排列,關鍵是如何篩選掉可能重複的排列。

這裡,我們可以首先將陣列進行排序,這樣就可以使得相同的元素是相鄰的,也就減少了我們處理的複雜度。更具體地,我們可以在列舉下標的時候判斷前一個元素是否是相同的,如果前一個元素沒有遍歷過而且是與當前元素相同,那麼可以跳過當前元素,因為當前元素一定會被前一個元素列舉在內,這樣就達到了去重的目的。

class Solution {
    boolean[] vis;// 記錄已經遍歷過的位置下標
    List<List<Integer>> result;
    public List<List<Integer>> permuteUnique(int[] nums) {
        vis = new boolean[nums.length];
        result = new LinkedList<>();
        Arrays.sort(nums);
        dfs(nums, 0, new LinkedList<Integer>());
        return result;
    }

    private void dfs(int[] nums, int num, LinkedList<Integer> list){
        int n = nums.length;
        if(num == n){
            result.add(new LinkedList<Integer>(list));
            return;
        }
        for(int i=0; i<n; i++){
            if(vis[i] || (i > 0 && !vis[i-1] && nums[i] == nums[i-1])){
                continue;
            }
            vis[i] = true;
            list.add(nums[i]);
            dfs(nums, num+1, list);
            list.removeLast();
            vis[i] = false;
        }
    }
}