LeetCode_78(回溯)

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

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

示例:

输入: nums = [1,2,3]
输出:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]
        这道题有两种做法,一种是二进制法,另一种是回溯法。二进制法比较好理解,这道题求一个数组的所有子集,在一个子集中,每个数都有选和不选两种状态,那么就可以用一个二进制串来表示子集中数组中每个数被选了还是没有被选。数组有n个元素,那么就有2^n个二进制串,每一个子串代表一个子集。那么我们可以从0到2^n循环,判断每一位是0还是1,若是1,则将这个数加入子集中。代码如下:

class Solution {
    public List> subsets(int[] nums) {
        List> res = new ArrayList<>();
        int num = (int) Math.pow(2, nums.length);
        int len = nums.length;
        for (int i = 0; i < num; i++) {
            List temp = new ArrayList<>();
            for (int j = 0; j < len; j++) {
                if (((i >> j) & 1) == 1)
                    temp.add(nums[j]);
            }
            res.add(temp);
        }
        return res;
    }
}


        这种方法需要判断一个数的每位二进制的值,我用到了两个位运算符>>和&,在我的另一篇文章里介绍过十进制与二进制转换的方法,与此处用到的方法大同小异。二进制和十进制相互转换的简便方法

        回溯法较为难理解,首先我们需要一个变量来记录我遍历过的结点,然后需要一个临时列表来储存当前得到的子集。通过变量来对数组进行遍历,每次遍历一个点便将他存入临时列表中,每次遍历到一种新路径,便将临时列表存入结果列表中,并且删掉当前结点遍历下一个结点,防止出现重复。代码如下:

class Solution {
    public List> subsets(int[] nums) {
        List> res = new ArrayList<>();
        List temp = new ArrayList<>();
        dfs(res, temp, 0, nums);
        return res;
    }
 
    void dfs(List> res, List temp, int pos, int[] a) {
        res.add(new ArrayList(temp));//另一个作用是在结果列表中存入空集
        for (int i = pos; i < a.length; i++) {
            temp.add(a[i]);
            dfs(res, temp, i + 1, a);
            temp.remove(temp.size() - 1);
        }
    }
}

 

你可能感兴趣的:(LeetCode题解,回溯)