二进制枚举子集(一)

17 篇文章 0 订阅

我们经常会碰到这样的问题:给定一个集合,枚举其所有可能的子集。当然,方法有很多,这里先介绍一种最简单的枚举方法----二进制法.

基本思想

思想很简单,我们可以用二进制的一位对应某一元素的选取状态,1表示选取,0表示未选取。

举个例子,假如要枚举{1, 2, 3, 4, 5}的所有子集,首先我们知道,其子集个数为 2 5 2^5 25个 ,也即从000001111132个,那么二进制01101就表示{2, 3, 5}

二进制数位12345
二进制数值01101
选取的元素-23-5

基于上述,我们的关键是要知道一个二进制数有哪些位是1?
那么有一个基本技巧,假设一个二进制数为num,我们只需要将num1 << j进行与(&)操作,就能判断num的第j位数字是否为1

比如:

num = 11, j = 3
num的二进制表示为1011, 1 << j 的二进制表示为1000
1011 & 1000 = 1000 ≠ 0,那么可以得出num二进制表示的第3位(最低位记为第0位)上的数字为1

num = 11, j = 2
num的二进制表示为1011, 1 << j 的二进制表示为0100
1011 & 0100 = 0000 = 0,那么可以得出num二进制表示的第2位上的数字为0.

核心代码

	// 给定集合nums: [1, 2, 3]
	int n = nums.length;
    List<List<Integer>> res = new ArrayList<>();
    // 大小为n的集合子集可用1 << n 种二进制数值表示, 取值区间为[0, 1 << n)
    for (int i = 0; i < (1 << n); i++) { 
		List<Integer> list = new ArrayList<>();
		for (int j = 0; j < n; j++) {  
			if ((i & (1 << j)) != 0) {   // 表示下标为j的元素是否被选取
				list.add(nums[j]);
			}
		}
	    res.add(list);
    }

res:
[
  [],
  [1],
  [1,2],
  [1,2,3],
  [1,3],
  [2],
  [2,3],
  [3]
]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值