LC排列组合类问题总结

最最常见的不过四种:
给定一个无重复/有重复的数组,输出其所有的排列/组合
解决方法大致上也是构建递归树 进行合理剪枝
LC46 无重复元素的排列
LC47 有重复元素的排列
LC77 无重复元素的组合

subset问题:
LC78 无重复元素的子集
LC90 有重复元素的子集

下面是代码:

public static List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        if (nums == null || nums.length == 0) return res;
        helper(res, new ArrayList<>(), nums);
        return res;
    }

    public static void helper(List<List<Integer>> res, List<Integer> list, int[] nums) { //递归函数有三个参数 总的res(nested list) res的基本组成单位
        if (list.size() == nums.length) { //触底警告!
            res.add(new ArrayList<>(list));
            return;
        }
        for (int i = 0; i < nums.length; i++) { //for loop递归 为什么要用for 因为每一层递归我们都要试一遍所有的 将没加过的加进去
            if (list.contains(nums[i])) continue;  // O(n)
            list.add(nums[i]);//前面是一直再加 也就是符合一直在push 进栈
            helper(res, list, nums);
            list.remove(list.size() - 1);//后面的弹出是在出栈,为什么要出栈,是因为我们在这个过程中重复利用了list这个变量
        }
    }
public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        if (nums == null || nums.length == 0) return  res;
        Arrays.sort(nums);//没要求时间复杂度 因此要进行预排序
        helper(res, new ArrayList<>(), nums, new boolean[nums.length]);
        return res;
    }

    public void helper(List<List<Integer>> res, List<Integer> list, int[] nums, boolean[] used) {
        if (list.size() == nums.length) {
            res.add(new ArrayList<>(list));
        }
        for (int i = 0; i < nums.length; i++) {
            if (used[i] || i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) continue;//如果i被标记为true 或者
            used[i] = true;//添加前标记一下
            list.add(nums[i]);
            helper(res, list, nums, used);
            used[i] = false;
            list.remove(list.size() - 1);
        }
    }
//组合的输入与之前略有不同 但是本质都一样
public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> res = new ArrayList<>();
        helper(res, new ArrayList<>(), n, k, 1);
        return res;
    }

    public void helper(List<List<Integer>> res, List<Integer> list, int n, int k, int start) {
        if (k == 0) {
            res.add(new ArrayList<>(list));//因为规定了list是个List 所以要转换一下?list为什么不可以直接定义ArrayList呢?
            return;
        }
        for (int i = start; i <= n; i++) { //之前的排列 这儿每次都是从1开始到n 然后在内部剪掉已经存在的枝,现在的组合因为是按照顺序来的 因此每一次都要进行不一样的剪枝
            list.add(i);
            helper(res, list, n, k - 1, i + 1);
            list.remove(list.size() - 1);//返回上一层
        }
    }
public static List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        if (nums == null || nums.length == 0) return res;
        helper(res, new ArrayList<>(), nums, 0);
        return res;
    }

    public static void helper(List<List<Integer>> res, List<Integer> list, int[] nums, int index) {
        res.add(new ArrayList<>(list));
        for (int i = index; i < nums.length; i++) { //排列组合算法的核心还保留着
            list.add(nums[i]);
            helper(res, list, nums, i + 1);
            list.remove(list.size() - 1);
        }
    }

    public List<List<Integer>> subsets2(int[] nums) {
        int length = nums.length;
        int size = (int) Math.pow(2, length);
        List<List<Integer>> subsets = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            subsets.add(new ArrayList<>());//首先初始化一个二维数组subset,初始化长度为2的length次方 因为2的length次方就是subset的个数
        }

        for (int i = 0; i < length; i++) { //
            for (int j = 0; j < size; j++) { //按照顺序写入subset
                if ((j >> i & 1) == 1) {//只有j>>i是奇数 这个if语句才成立 虽然不明白原理 但是跑一下case 是对的
                    subsets.get(j).add(nums[i]);
                }
            }
        }
        return subsets;
    }
public static List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        if (nums == null || nums.length == 0) return res;
        Arrays.sort(nums);
        helper(res, new ArrayList<>(), nums, 0);
        return res;
    }
    public static void helper(List<List<Integer>> res, List<Integer> list, int[] nums, int index) {
        res.add(new ArrayList<>(list));
        for (int i = index; i < nums.length; i++) {
            if (i != index && nums[i] == nums[i - 1]) continue;
            list.add(nums[i]);
            helper(res, list, nums, i + 1);
            list.remove(list.size() - 1);
        }
    }

此外 还有LC93

posted @ 2020-04-26 23:02  EvanMeetTheWorld  阅读(31)  评论(0)    收藏  举报