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;
        }
    }
}
posted @ 2022-04-07 21:09  Garrett_Wale  阅读(95)  评论(0编辑  收藏  举报