1994. The Number of Good Subsets
Description
You are given an integer array nums
. We call a subset of nums
good if its product can be represented as a product of one or more distinct prime numbers.
- For example, if
nums = [1, 2, 3, 4]
:[2, 3]
,[1, 2, 3]
, and[1, 3]
are good subsets with products6 = 2*3
,6 = 2*3
, and3 = 3
respectively.[1, 4]
and[4]
are not good subsets with products4 = 2*2
and4 = 2*2
respectively.
Return the number of different good subsets in nums
modulo109 + 7
.
A subset of nums
is any array that can be obtained by deleting some (possibly none or all) elements from nums
. Two subsets are different if and only if the chosen indices to delete are different.
Example 1:
Input: nums = [1,2,3,4] Output: 6 Explanation: The good subsets are: - [1,2]: product is 2, which is the product of distinct prime 2. - [1,2,3]: product is 6, which is the product of distinct primes 2 and 3. - [1,3]: product is 3, which is the product of distinct prime 3. - [2]: product is 2, which is the product of distinct prime 2. - [2,3]: product is 6, which is the product of distinct primes 2 and 3. - [3]: product is 3, which is the product of distinct prime 3.
Example 2:
Input: nums = [4,2,3,15] Output: 5 Explanation: The good subsets are: - [2]: product is 2, which is the product of distinct prime 2. - [2,3]: product is 6, which is the product of distinct primes 2 and 3. - [2,15]: product is 30, which is the product of distinct primes 2, 3, and 5. - [3]: product is 3, which is the product of distinct prime 3. - [15]: product is 15, which is the product of distinct primes 3 and 5.
Constraints:
1 <= nums.length <= 105
1 <= nums[i] <= 30
Solutions
Solution: Dynamic Programming + Bit Manipulation
- Time complexity: O(210)
- Space complexity: O(210)
JavaScript
js
/**
* @param {number[]} nums
* @return {number}
*/
const numberOfGoodSubsets = function (nums) {
const MOD = BigInt(10 ** 9 + 7);
const freq = Array.from({ length: 31 }, () => 0n);
const primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29];
const masks = Array.from({ length: 31 }, () => -1);
for (const num of nums) {
freq[num] += 1n;
}
for (let num = 2; num <= 30; num++) {
let mask = 0;
let current = num;
let valid = true;
for (const [index, prime] of primes.entries()) {
let count = 0;
while (current % prime === 0) {
current /= prime;
count++;
}
if (count > 1) {
valid = false;
break;
}
if (count === 1) {
mask |= 1 << index;
}
}
if (valid) {
masks[num] = mask;
}
}
const dp = Array.from({ length: 1 << primes.length }, () => 0n);
dp[0] = 1n;
for (let num = 2; num <= 30; num++) {
if (freq[num] === 0n || masks[num] === -1) continue;
const mask = masks[num];
for (let state = (1 << primes.length) - 1; state >= 0; state--) {
if ((state & mask) === 0) {
dp[state | mask] = (dp[state | mask] + dp[state] * freq[num]) % MOD;
}
}
}
let result = 0n;
for (let state = 1; state < 1 << primes.length; state++) {
result = (result + dp[state]) % MOD;
}
if (freq[1] > 0n) {
result = (result * modPow(2n, freq[1], MOD)) % MOD;
}
return Number(result);
};
function modPow(base, exp, mod) {
let res = 1n;
while (exp > 0n) {
if (exp & 1n) {
res = (res * base) % mod;
}
base = (base * base) % mod;
exp >>= 1n;
}
return res;
}