LeetCode 题解工作台

无平方子集计数

给你一个正整数数组 nums 。 如果数组 nums 的子集中的元素乘积是一个 无平方因子数 ,则认为该子集是一个 无平方 子集。 无平方因子数 是无法被除 1 之外任何平方数整除的数字。 返回数组 nums 中 无平方 且 非空 的子集数目。因为答案可能很大,返回对 10 9 + 7 取余的结果。…

category

5

题型

code_blocks

5

代码语言

hub

3

相关题

当前训练重点

中等 · 状态·转移·动态规划

bolt

答案摘要

注意到题目中 的范围为 $[1, 30]$,因此我们可以预处理出所有小于等于 的质数,即 $[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]$。 无平方子集中,所有元素的乘积可以表示为一个或多个互不相同的质数的乘积,也即是说,每个质因数最多只能出现一次。因此,我们可以使用一个二进制数来表示一个子集中的质因数,其中二进制数的第 位表示质数 是否出现在子集中。

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一个正整数数组 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 <= 1000
  • 1 <= nums[i] <= 30
lightbulb

解题思路

方法一:状态压缩动态规划

注意到题目中 nums[i]nums[i] 的范围为 [1,30][1, 30],因此我们可以预处理出所有小于等于 3030 的质数,即 [2,3,5,7,11,13,17,19,23,29][2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

无平方子集中,所有元素的乘积可以表示为一个或多个互不相同的质数的乘积,也即是说,每个质因数最多只能出现一次。因此,我们可以使用一个二进制数来表示一个子集中的质因数,其中二进制数的第 ii 位表示质数 primes[i]primes[i] 是否出现在子集中。

我们可以使用状态压缩动态规划的方法来求解本题。设 f[i]f[i] 表示二进制数 ii 表示的子集中的质因数的乘积为一个或多个互不相同的质数的乘积的方案数。初始时 f[0]=1f[0]=1

我们在 [2,..30][2,..30] 的范围内枚举一个数 xx,如果 xx 不在 numsnums 中,或者 xx4,9,254, 9, 25 的倍数,那么我们可以直接跳过。否则,我们可以将 xx 的质因数用一个二进制数 maskmask 表示,然后我们从大到小枚举当前的状态 statestate,如果 statestatemaskmask 按位与的结果为 maskmask,那么我们可以从状态 f[statemask]f[state \oplus mask] 转移到状态 f[state]f[state],转移方程为 f[state]=f[state]+cnt[x]×f[statemask]f[state] = f[state] + cnt[x] \times f[state \oplus mask],其中 cnt[x]cnt[x] 表示 xxnumsnums 中出现的次数。

注意,我们没有从数字 11 开始枚举,因为我们可以选择任意个数字 11,加入到无平方子集中。也可以只选择任意个数字 11,不加入到无平方子集中,这两种情况都是合法的。那么答案就是 (i=02101f[i])1(\sum_{i=0}^{2^{10}-1} f[i]) - 1

时间复杂度 O(n+C×M)O(n + C \times M),空间复杂度 O(M)O(M)。其中 nnnumsnums 的长度;而 CCMM 分别为题目中 nums[i]nums[i] 的范围和状态的个数,本题中 C=30C=30, M=210M=2^{10}

相似题目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
speed

复杂度分析

指标
时间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
psychology

面试官常问的追问

外企场景
  • 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.

warning

常见陷阱

外企场景
  • 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.

swap_horiz

进阶变体

外企场景
  • 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.

help

常见问题

外企场景

无平方子集计数题解:状态·转移·动态规划 | LeetCode #2572 中等