算法题分享 | 全排列 II

34 阅读3分钟

今日iPad壁纸📖文字篇17_1_舞木子_来自小红书网页版.jpg

题目

给定一个可包含重复数字的序列 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

题解

解题思路

全排列问题可以使用回溯算法来解决。

假设数组的长度为 n,我们把 n 个元素分别填充到不同的位置上即得到一个排列组合,因此可以从 0 到 n - 1 的位置逐个填充,每次递归都尝试选定当前位置所有可填充的元素,然后再进一步递归填充下一个位置,最终,填完完最后一个位置即可得到一个排列,添加到结果集合中即可。

若数组中不存在重复的元素,使用以上的做法已经可以解决问题了,但是本题说明了存在重复的元素,因此我们需要解决最终的排列集合中可能会存在重复全排列的问题。

什么原因导致出现重复的全排列呢?
这里以数组 nums = [3,3,0,3] 举例,假如在填充第 0 个位置时选中了 nums[1],那么最终的得到的全排列当中一定存和在第 0 个位置时选中了 nums[3] 或 nums[0] 的重复的全排列,因此,我们需要确保的是,在同一个位置,相同的元素只选一次。

我们可以先对数组进行排序,确保相同的元素相邻,这样每次递归时,可以先判断前一个元素是否和当前元素相同并且没有被选中,如果是,直接跳过该元素,因为在遍历前面的元素时,肯定已经尝试过把该元素填充到当前位置,这里要是再选就会导致出现重复了。

代码

class Solution {

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

    public List<List<Integer>> permuteUnique(int[] nums) {
        int n = nums.length;
        boolean[] flags = new boolean[n];
        Arrays.sort(nums);
        backtrack(new ArrayList<Integer>(), nums, flags, 0);
        return ans;
    }

    public void backtrack(List<Integer> cur, int[] nums, boolean[] flags, int idx) {
        if (idx == nums.length) {
            ans.add(new ArrayList(cur));
            return;
        }

        for (int i = 0; i < nums.length; i++) {
            if (flags[i] || (i > 0 && !flags[i - 1] && nums[i] == nums[i - 1])) {
                continue;
            }

            flags[i] = true;
            cur.add(nums[i]);
            backtrack(cur, nums, flags, idx + 1);

            flags[i] = false;
            cur.remove(cur.size() - 1);

        }

    }
}

复杂度分析

  • 时间复杂度:O(n * n!)
    其中 n 是数组的长度,回溯时一共搜索了 n! 条路径,对于每个全排列(路径),需要把全排列复制进结果集合 中,这需要 O(n) 的时间复杂度,因此一共是 O(n * n!)。
  • 空间复杂度:O(n) 其中 cur 数组的开销是 O(n),递归的栈空间开销是 O(n),所以一共是 O(n + n) = O(2n) = O(n)。

优质项目推荐

推荐一个可用于练手、毕业设计参考、增加简历亮点的项目。

lemon-puls/txing-oj-backend: Txing 在线编程学习平台,集在线做题、编程竞赛、即时通讯、文章创作、视频教程、技术论坛为一体

公众号

有兴趣可以关注公众号一起学习更多的干货哈!

扫码_搜索联合传播样式-白色版.png