【算法题解】统计按位或最大值子集的数量 —— 子集按位或最大值计数问题
题目描述.
给定一个整数数组 nums,请你找出 nums 所有非空子集按位或(bitwise OR)可能得到的最大值,并返回按位或能得到最大值的不同非空子集的数目。
- 子集定义:如果数组
a可以由数组b删除一些元素(或不删除)得到,则认为a是b的一个子集。 - 子集不同定义:如果选中的元素下标位置不一样,则认为两个子集不同。
- 按位或定义:对于数组
a,其按位或为a[0] OR a[1] OR ... OR a[a.length-1]。
输入输出示例
示例 1:
输入:nums = [3,1]
输出:2
解释:
所有非空子集的按位或值:
- [3] -> 3
- [1] -> 1
- [3,1] -> 3 OR 1 = 3
最大按位或值是3,能得到3的子集有2个:[3], [3,1]
示例 2:
输入:nums = [2,2,2]
输出:7
解释:
所有非空子集的按位或均为2,总共有 2^3 - 1 = 7 个非空子集
示例 3:
输入:nums = [3,2,1,5]
输出:6
解释:
最大按位或值为7,能得到7的子集有6个:
- [3,5]
- [3,1,5]
- [3,2,5]
- [3,2,1,5]
- [2,5]
- [2,1,5]
解题分析
本题核心在于:
- 求所有非空子集按位或的最大值 max_or。
- 统计所有按位或等于 max_or 的子集个数。
题目对数组长度最大为16,意味着可以考虑用穷举所有子集的方法。
子集数量
- 数组长度为
n,非空子集数量为2^n - 1。 - 最大16长度时,子集数量约为 65535,枚举可接受。
按位或的性质
- 按位或是单调递增的:子集包含更多元素时按位或值只会变大或保持不变。
- 不需要特别排序,只需遍历所有子集,计算按位或。
解题方法
方法一:位掩码枚举
使用位掩码从 1 到 (1 << n) - 1 遍历所有非空子集。
- 对每个子集,计算按位或。
- 维护最大按位或值
max_or。 - 统计按位或等于
max_or的子集数量。
代码实现(Python)
from typing import List
class Solution:
def countMaxOrSubsets(self, nums: List[int]) -> int:
n = len(nums)
max_or = 0
count = 0
# 遍历所有非空子集
for mask in range(1, 1 << n):
or_val = 0
for i in range(n):
if mask & (1 << i):
or_val |= nums[i]
# 更新最大按位或及计数
if or_val > max_or:
max_or = or_val
count = 1
elif or_val == max_or:
count += 1
return count
复杂度分析
- 时间复杂度:O(n×2n)O(n \times 2^n),
- 枚举子集 2n2^n 个,每个子集最多计算 nn 个元素按位或。
- 空间复杂度:O(1)O(1) 额外空间。
对于 n≤16n \leq 16,性能足够。
示例说明
以 nums = [3,2,1,5] 为例:
- 枚举非空子集,计算按位或:
- 子集
[3,5],按位或为3 | 5 = 7 - 子集
[3,1,5],按位或为3 | 1 | 5 = 7 - …
- 子集
- 找出最大按位或
7,统计有多少子集按位或等于7,答案为6。
方法扩展与优化
- 回溯剪枝:可以用回溯递归,从左到右决定选或不选某元素,动态维护当前按位或值。遇到已经达到最大可能按位或值时,可以提前剪枝。
- 预计算整体按位或上界:先求整个数组的按位或
total_or,作为最大值的上限。 - 存储中间结果:若题目改成要求返回所有最大按位或子集的集合,可能需要存储对应子集。
总结
本题利用位掩码枚举所有非空子集,计算其按位或,并统计最大按位或子集数量,解法直接且高效。
对于限制在16的规模,枚举全部子集完全可行,且代码易于理解和实现。
1102

被折叠的 条评论
为什么被折叠?



