LeetCode 题解工作台
无平方子集计数
给你一个正整数数组 nums 。 如果数组 nums 的子集中的元素乘积是一个 无平方因子数 ,则认为该子集是一个 无平方 子集。 无平方因子数 是无法被除 1 之外任何平方数整除的数字。 返回数组 nums 中 无平方 且 非空 的子集数目。因为答案可能很大,返回对 10 9 + 7 取余的结果。…
5
题型
5
代码语言
3
相关题
当前训练重点
中等 · 状态·转移·动态规划
答案摘要
注意到题目中 的范围为 $[1, 30]$,因此我们可以预处理出所有小于等于 的质数,即 $[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]$。 无平方子集中,所有元素的乘积可以表示为一个或多个互不相同的质数的乘积,也即是说,每个质因数最多只能出现一次。因此,我们可以使用一个二进制数来表示一个子集中的质因数,其中二进制数的第 位表示质数 是否出现在子集中。
Interview AiBoxInterview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路
题目描述
给你一个正整数数组 nums 。
如果数组 nums 的子集中的元素乘积是一个 无平方因子数 ,则认为该子集是一个 无平方 子集。
无平方因子数 是无法被除 1 之外任何平方数整除的数字。
返回数组 nums 中 无平方 且 非空 的子集数目。因为答案可能很大,返回对 109 + 7 取余的结果。
nums 的 非空子集 是可以由删除 nums 中一些元素(可以不删除,但不能全部删除)得到的一个数组。如果构成两个子集时选择删除的下标不同,则认为这两个子集不同。
示例 1:
输入:nums = [3,4,4,5] 输出:3 解释:示例中有 3 个无平方子集: - 由第 0 个元素 [3] 组成的子集。其元素的乘积是 3 ,这是一个无平方因子数。 - 由第 3 个元素 [5] 组成的子集。其元素的乘积是 5 ,这是一个无平方因子数。 - 由第 0 个和第 3 个元素 [3,5] 组成的子集。其元素的乘积是 15 ,这是一个无平方因子数。 可以证明给定数组中不存在超过 3 个无平方子集。
示例 2:
输入:nums = [1] 输出:1 解释:示例中有 1 个无平方子集: - 由第 0 个元素 [1] 组成的子集。其元素的乘积是 1 ,这是一个无平方因子数。 可以证明给定数组中不存在超过 1 个无平方子集。
提示:
1 <= nums.length <= 10001 <= nums[i] <= 30
解题思路
方法一:状态压缩动态规划
注意到题目中 的范围为 ,因此我们可以预处理出所有小于等于 的质数,即 。
无平方子集中,所有元素的乘积可以表示为一个或多个互不相同的质数的乘积,也即是说,每个质因数最多只能出现一次。因此,我们可以使用一个二进制数来表示一个子集中的质因数,其中二进制数的第 位表示质数 是否出现在子集中。
我们可以使用状态压缩动态规划的方法来求解本题。设 表示二进制数 表示的子集中的质因数的乘积为一个或多个互不相同的质数的乘积的方案数。初始时 。
我们在 的范围内枚举一个数 ,如果 不在 中,或者 为 的倍数,那么我们可以直接跳过。否则,我们可以将 的质因数用一个二进制数 表示,然后我们从大到小枚举当前的状态 ,如果 与 按位与的结果为 ,那么我们可以从状态 转移到状态 ,转移方程为 ,其中 表示 在 中出现的次数。
注意,我们没有从数字 开始枚举,因为我们可以选择任意个数字 ,加入到无平方子集中。也可以只选择任意个数字 ,不加入到无平方子集中,这两种情况都是合法的。那么答案就是 。
时间复杂度 ,空间复杂度 。其中 为 的长度;而 和 分别为题目中 的范围和状态的个数,本题中 , 。
相似题目:
class Solution:
def squareFreeSubsets(self, nums: List[int]) -> int:
primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
cnt = Counter(nums)
mod = 10**9 + 7
n = len(primes)
f = [0] * (1 << n)
f[0] = pow(2, cnt[1])
for x in range(2, 31):
if cnt[x] == 0 or x % 4 == 0 or x % 9 == 0 or x % 25 == 0:
continue
mask = 0
for i, p in enumerate(primes):
if x % p == 0:
mask |= 1 << i
for state in range((1 << n) - 1, 0, -1):
if state & mask == mask:
f[state] = (f[state] + cnt[x] * f[state ^ mask]) % mod
return sum(v for v in f) % mod - 1
复杂度分析
| 指标 | 值 |
|---|---|
| 时间 | complexity is O(n * 2^10) since there are 10 primes under 30 and we iterate over each array element updating compatible bitmask states. Space complexity is O(2^10) for the DP states array. |
| 空间 | Depends on the final approach |
面试官常问的追问
外企场景- question_mark
Recognize this as a subset counting problem with constraints on multiplicative combinations.
- question_mark
Expect the candidate to optimize with bitmask DP to avoid O(2^n) brute force.
- question_mark
Look for handling of edge numbers like 1 and duplicates efficiently.
常见陷阱
外企场景- error
Failing to use bitmasks leads to slow subset enumeration for arrays of size 1000.
- error
Ignoring repeated primes in a product may incorrectly count non-square-free subsets.
- error
Forgetting to handle 1 separately can undercount valid subsets.
进阶变体
外企场景- arrow_right_alt
Count subsets whose product is divisible by a given set of primes without repeats.
- arrow_right_alt
Count square-free subsets in multi-dimensional arrays or matrices.
- arrow_right_alt
Modify problem to count subsets with product coprime to a given integer.