Problem
You are given a positive integer 0-indexed array nums
.
A subset of the array nums
is square-free if the product of its elements is a square-free integer.
A square-free integer is an integer that is divisible by no square number other than 1
.
Return the number of square-free non-empty subsets of the array nums. Since the answer may be too large, return it modulo 109 + 7
.
A non-empty subset of nums
is an array that can be obtained by deleting some (possibly none but not all) elements from nums
. Two subsets are different if and only if the chosen indices to delete are different.
Example 1:
Input: nums = [3,4,4,5]
Output: 3
Explanation: There are 3 square-free subsets in this example:
- The subset consisting of the 0th element [3]. The product of its elements is 3, which is a square-free integer.
- The subset consisting of the 3rd element [5]. The product of its elements is 5, which is a square-free integer.
- The subset consisting of 0th and 3rd elements [3,5]. The product of its elements is 15, which is a square-free integer.
It can be proven that there are no more than 3 square-free subsets in the given array.
Example 2:
Input: nums = [1]
Output: 1
Explanation: There is 1 square-free subset in this example:
- The subset consisting of the 0th element [1]. The product of its elements is 1, which is a square-free integer.
It can be proven that there is no more than 1 square-free subset in the given array.
Constraints:
1 <= nums.length <= 1000
1 <= nums[i] <= 30
Solution (Java)
import java.math.BigInteger;
class Solution {
/*
Runtime 3 ms Beats 100%
Memory 41.5 MB Beats 100%
*/
private final int MOD = (int) (1e9 + 7);
private final List<Integer> PRIMES = List.of(2, 3, 5, 7, 11, 13);
public int squareFreeSubsets(int[] nums) {
int[] primeFactors = new int[31];
for (int i = 2; i <= 30; i++) {
if (i % 4 == 0 || i % 9 == 0 || i % 25 == 0) {
continue;
}
for (int j = 0; j < PRIMES.size(); j++) {
if (i % PRIMES.get(j) == 0) {
primeFactors[i] += 1 << j;
}
}
}
int[] freqs = new int[31];
for (int num : nums) {
if (num % 4 == 0 || num % 9 == 0 || num % 25 == 0) {
continue;
}
freqs[num]++;
}
int mask = 0;
int[][] cache = new int[31][1<<6];
for (int[] row : cache) {
Arrays.fill(row, -1);
}
long oneSubsets = BigInteger.TWO.modPow(BigInteger.valueOf(freqs[1]), BigInteger.valueOf(MOD)).longValue();
int otherSubsets = (int) (squareFreeSubsets(freqs, primeFactors, 2, mask, cache) % MOD);
return (int) (otherSubsets * oneSubsets % MOD + oneSubsets - 1) % MOD;
}
private long squareFreeSubsets(int[] freqs, int[] primeFactors, int num, int mask, int[][] cache) {
if (num == 30) {
if ((primeFactors[num] & mask) != 0) {
return 0;
}
return freqs[num];
}
if (cache[num][mask] != -1) {
return cache[num][mask];
}
long countWithout = squareFreeSubsets(freqs, primeFactors, num + 1, mask, cache) % MOD;
if (freqs[num] == 0 || (primeFactors[num] & mask) != 0) {
cache[num][mask] = (int) countWithout;
return countWithout;
}
long countWith = freqs[num] + freqs[num] * squareFreeSubsets(freqs, primeFactors, num + 1, primeFactors[num] | mask, cache) % MOD;
countWith %= MOD;
cache[num][mask] = (int) ((countWithout + countWith) % MOD);
return (countWithout + countWith) % MOD;
}
}
Explain:
nope.
Complexity:
- Time complexity : O(n).
- Space complexity : O(n).