【LeetCode】78. 子集(Java)

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

这道题做完后,可以再做做90. 子集 II

解法一

迭代

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        //放入一个空集合
        result.add(new ArrayList<>());

        //遍历所有数字
        for (int num : nums) {
            //遍历所有小集合
            int size = result.size();
            for (int i = 0; i < size; i++) {
                //在小集合原先的基础上,再加上当前值,然后保存到大集合里
                List<Integer> list = new ArrayList<>(result.get(i));
                list.add(num);
                result.add(list);
            }
        }
        //     添加前的大集合  多添加的小集合       添加后的大集合
        //第一轮:  []      -> [1]          -> [],[1]
        //第二轮:  [], [1] -> [2], [1,2]   -> [],[1],[2],[1,2]
        //....
        return result;
    }
}

在这里插入图片描述

解法二

回溯

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        //回溯
        List<List<Integer>> res = new ArrayList<>();
        backtrack(nums, 0, res, new ArrayList<>());
        return res;
    }

    //回溯
    private void backtrack(int[] nums, int start, List<List<Integer>> res, List<Integer> cur) {
    	//把递归过来的cur添加到res中
    	//这一步添加并不是添加当前这个方法,而是添加上一个方法递归传递过来的cur
        res.add(new ArrayList<>(cur));
        //如果start == num.length,那么下面这个循环不会执行,只执行上面的添加操作
        //即,当start == num.length时为出口
        for (int i = start; i < nums.length; i++) {
        	//递归的第一个方法,当前cur为空集合,添加一个(上一轮为空,本轮集合内的个数为1)
            cur.add(nums[i]);
            //那么,第二个方法为2个数(下一轮轮集合内的个数为2)
            backtrack(nums, i + 1, res, cur);
            //要移除添加的值(保证本轮的集合内个数为1,即要保证下次循环添加后集合内的个数也是为1)
            cur.remove(cur.size() - 1);
        }
    }
}

在这里插入图片描述
解法二和解法三,是看题解区数据结构和算法写的题解,加的注释如果看不懂就请忽略吧,本人也是个菜鸟,只能根据自己的理解写注释,看不懂的话,DeBug一步一步走,慢慢熟悉。

解法三

DFS(深度优先搜索)

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        //DFS(深度优先搜索)
        List<List<Integer>> res = new ArrayList<>();
        //因为DFS是一个一个去遍历,所以不会有空的集合,需要自己添加
        res.add(new ArrayList<>());
        preOrder(nums, 0, res, new ArrayList<>());
        return res;
    }

	//DFS(深度优先搜索)
    public static void preOrder(int[] nums, int i, List<List<Integer>> res, ArrayList<Integer> subset) {
        if (i >= nums.length) return;
        // 到了新的状态,记录新的路径,要重新拷贝一份
        subset = new ArrayList<Integer>(subset);

        // 这里因为是内存传递,所以保存到res的subset会因为下面的subset的修改而修改
        // 1. 前序遍历,先添加,然后修改
        res.add(subset);
        //递归
        preOrder(nums, i + 1, res, subset);
        subset.add(nums[i]);
        // 2. 把添加操作放这里也是可以的,这是中序遍历
        // res.add(subset);
        //递归
        preOrder(nums, i + 1, res, subset);
        // 3. 后序遍历
        // res.add(subset);
    }
}

在这里插入图片描述
不熟悉的回溯和DFS的话,需要多做些类似的题目,找找感觉。本人目前也在找感觉中o(╥﹏╥)o。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值