leetcode-1994:好子集的数目

简介: leetcode-1994:好子集的数目

题目

题目链接

给你一个整数数组 nums 。如果 nums 的一个子集中,所有元素的乘积可以表示为一个或多个 互不相同的质数 的乘积,那么我们称它为 好子集 。

  • 比方说,如果 nums = [1, 2, 3, 4] :
    [2, 3] ,[1, 2, 3] 和 [1, 3] 是 好 子集,乘积分别为 6 = 23 ,6 = 23 和 3 = 3 。
    [1, 4] 和 [4] 不是 好 子集,因为乘积分别为 4 = 22 和 4 = 22 。
    请你返回 nums 中不同的 好 子集的数目对 109 + 7 取余 的结果。

nums 中的 子集 是通过删除 nums 中一些(可能一个都不删除,也可能全部都删除)元素后剩余元素组成的数组。如果两个子集删除的下标不同,那么它们被视为不同的子集。

示例 1:

输入:nums = [1,2,3,4]
输出:6
解释:好子集为:
- [1,2]:乘积为 2 ,可以表示为质数 2 的乘积。
- [1,2,3]:乘积为 6 ,可以表示为互不相同的质数 2 和 3 的乘积。
- [1,3]:乘积为 3 ,可以表示为质数 3 的乘积。
- [2]:乘积为 2 ,可以表示为质数 2 的乘积。
- [2,3]:乘积为 6 ,可以表示为互不相同的质数 2 和 3 的乘积。
- [3]:乘积为 3 ,可以表示为质数 3 的乘积。

示例 2:

输入:nums = [4,2,3,15]
输出:5
解释:好子集为:
- [2]:乘积为 2 ,可以表示为质数 2 的乘积。
- [2,3]:乘积为 6 ,可以表示为互不相同质数 2 和 3 的乘积。
- [2,15]:乘积为 30 ,可以表示为互不相同质数 2,3 和 5 的乘积。
- [3]:乘积为 3 ,可以表示为质数 3 的乘积。
- [15]:乘积为 15 ,可以表示为互不相同质数 3 和 5 的乘积。

解题

方法一:状态压缩DP

参考链接

class Solution {
public:
    int MOD=1e9+7;
    vector<int> p={2,3,5,7,11,13,17,19,23,29};
    int numberOfGoodSubsets(vector<int>& nums) {
        int n=nums.size();
        vector<int> cnts(31,0); //题目规定数值相同,下标不同均视为不同方案,因此要统计每个数出现次数
        for(int num:nums) cnts[num]++;
        int mask=1<<10;
        vector<long> f(mask);//利用位来记录每个质数使用状态,以此进行状态压缩
        f[0]=1;
        for(int i=2;i<=30;i++){
            if(cnts[i]==0) continue;
            int cur=0,x=i;
            // 对 i 进行试除
            bool ok=true;
            for(int j=0;j<10;j++){
                int t=p[j],c=0;
                while(x%t==0){
                    cur|=(1<<j);
                    x/=t;
                    c++;
                }
                // 如果 i 能够被同一质数试除多次,说明 i 不能加到子集,跳过
                if(c>1){
                    ok=false;
                    break;
                }
            }
            if(!ok) continue;
            // 枚举前一状态 prev
            //(确保考虑一个新数值 i 时,依赖的子集 prev 存储的为尚未考虑 i 的方案数)
            for(int prev=0;prev<mask;prev++){
                // 只有当前选择数与前一状态不冲突,则能够进行转移,将方案数进行累加
                if((prev&cur)!=0) continue;
                f[prev|cur]=(f[prev|cur]+f[prev]*cnts[i])%MOD;
            }
        }
        long res=0;
        // 统计所有非空集的方案数(因为题目要求 子集数)
        for(int i=1;i<mask;i++) res=(res+f[i])%MOD;
        // 在此基础上,考虑每个 1 选择与否对答案的影响
        for(int i=0;i<cnts[1];i++) res=res*2%MOD;
        return res;
    }
};


相关文章
|
4月前
|
算法
LeetCode第90题子集II
LeetCode第90题"子集II"的解题方法,通过排序和回溯算法生成所有不重复的子集,并使用一个boolean数组来避免同一层中的重复元素,展示了解决这类问题的编码技巧。
LeetCode第90题子集II
|
4月前
|
Python
【Leetcode刷题Python】416. 分割等和子集
LeetCode 416题 "分割等和子集" 的Python解决方案,使用动态规划算法判断是否可以将数组分割成两个元素和相等的子集。
41 1
|
4月前
|
索引 Python
【Leetcode刷题Python】78. 子集
LeetCode题目78的Python编程解决方案,题目要求给定一个互不相同的整数数组,返回该数组所有可能的子集(幂集),且解集中不能包含重复的子集。
29 1
|
4月前
|
算法
LeetCode第78题子集
文章分享了LeetCode第78题"子集"的解法,使用递归和回溯算法遍历所有可能的子集,展示了将子集问题视为树形结构进行遍历的解题技巧。
|
5月前
|
存储 算法
经典的滑动窗口的题目 力扣 2799. 统计完全子数组的数目(面试题)
经典的滑动窗口的题目 力扣 2799. 统计完全子数组的数目(面试题)
|
5月前
2670.找出不同元素数目差数组-力扣(LeetCode)
2670.找出不同元素数目差数组-力扣(LeetCode)
38 0
|
6月前
|
机器学习/深度学习 存储 算法
LeetCode题目 90:五种算法 回溯\迭代\位掩码\字典树\动态规划实现 子集ll
LeetCode题目 90:五种算法 回溯\迭代\位掩码\字典树\动态规划实现 子集ll
|
6月前
|
存储 机器学习/深度学习 算法
力扣78题:生成子集
力扣78题:生成子集
|
7月前
[leetcode~数位动态规划] 2719. 统计整数数目 hard
[leetcode~数位动态规划] 2719. 统计整数数目 hard
|
7月前
|
算法
"刷题记录:哈希表+双指针 | leetcode-2465. 不同的平均值数目 "
该文段是一篇关于编程题目的解答,主要讨论如何找到数组中所有不同平均值的个数。作者首先使用排序和哈希集来解决,将数组转为列表排序后,通过双指针计算平均值并存入哈希集以去重。然后,作者发现可以优化方案,通过双指针在排序后的数组中直接计算两数之和,用哈希集记录不重复的和,从而避免实际计算平均值,提高了算法效率。最终代码展示了这两种方法。
64 0