leetcode刷题(23)——78. 子集

一、题目

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

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

示例:

输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]

二、思路及代码实现

方法一:回溯

  • 先将空集插入子集中;
  • 找到 1 开头的子集,有 [1],[1,2],[1,2,3],[1,3];
  • 回溯,至根节点,选择 2 ,找到 2 开头的子集,有 [2],[2,3];
  • 再回溯,至根节点,选择 3,找到 3 开头的子集,有 [3]。
class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> list = new ArrayList<>();
        backTrack(list, new ArrayList<Integer>(), nums, 0);
        return list;
    }

    public void backTrack(List<List<Integer>> list, List<Integer> tempList, int[] nums, int start){
        list.add(new ArrayList<>(tempList));
        for(int i = start; i < nums.length; i++){
            tempList.add(nums[i]);
            backTrack(list, tempList, nums, i + 1);
            tempList.remove(tempList.size() - 1);
        }
    }
}

方法二:字典排序(二进制排序)

该方法思路来自于官方题解。

基于二进制位掩码和对应位掩码之间的映射字典生成子集。对于含有 n 个数据的数组,其子集数为 2 n 2^n 2n 个。将每个子集映射到长度为 n 位的掩码中,若第 i 位掩码 nums[i] 为 1,表示第 i 个元素在子集中;若第 i 位掩码 nums[i] 为 0,表示第 i 个元素不在子集中。

例如,[1, 2, 3] 含有三个元素,就可以用 3 位的二进制掩码与 [1, 2, 3] 的子集建立映射关系,如下表所示:

二进制掩码对应的子集
000[]
001[3]
010[2]
011[2, 3]
100[1]
101[1, 3]
110[1, 2]
111[1, 2, 3]

因此,要找到所有子集,只需要生成从 0…00 到 1…11 的所有 n 位掩码。

需要注意的是, 必须生成固定长度的位掩码:例如 001,而不是 1。也就是如何处理左边填充 0 的问题,可以借助或运算。将 i 与 2 n 2^n 2n 进行或运算,因为 2 n 2^n 2n 的低 n 位均为 0,和 i 进行或运算后会保留 i 中的 1 而将其它位置零。比如上例, 2 3 = 8 2^3 = 8 23=8,则 1 | 8 = 1 | 1000 = 0001,截取其低三位就可得到 001。

代码如下:

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> list = new ArrayList<>();
        int k = (int)Math.pow(2, nums.length);
        for(int i = 0; i < k; i++){
        	// 获取对应的位掩码
            String bitmask = Integer.toBinaryString(i | k).substring(1);
            List<Integer> tempList = new ArrayList<>();
            for(int j = 0; j < nums.length; j++){
                if(bitmask.charAt(j) == '1')
                    tempList.add(nums[j]);
            }
            list.add(tempList);
        }
        return list;
    }
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值