LeetCode-1994 好子集的数目
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/the-number-of-good-subsets
题目描述
给你一个整数数组 nums 。如果 nums 的一个子集中,所有元素的乘积可以表示为一个或多个 互不相同的质数 的乘积,那么我们称它为 好子集 。
比方说,如果 nums = [1, 2, 3, 4] :
[2, 3] ,[1, 2, 3] 和 [1, 3] 是 好 子集,乘积分别为 6 = 2*3 ,6 = 2*3 和 3 = 3 。
[1, 4] 和 [4] 不是 好 子集,因为乘积分别为 4 = 2*2 和 4 = 2*2 。
请你返回 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 的乘积。
提示:
1 <= nums.length <= 105
1 <= nums[i] <= 30
解题思路
这道题是十分之难的一道综合题,啃了足足一天才完全搞懂。
首先根据提示,数据样本很多,暴力枚举肯定行不通。但是注意到一个很有意思的地方,数据样本中的数量很多,但是样本数据仅仅是1-30,这就是突破口。
首先可以得知,任何数乘1都为任何数,所以1是在好子集中仅存在有或没有两种状态。而1-30中的除1以外的质数为2,3,5,7,11,13,17,19,23,29.如果想要成为一个好的子集,那么就需要子集中因数只有这些质数并且质数出现的次数仅为一次。那么我们可以使用一个int的低10位来记录这十个质数的是否在子集中出现。
由于样本数量十分大,但是实际上有许多重复的数据,所以可以使用计数的方法,将相同的数字使用一个vector统计出来,我这里使用了viCount,数组下标表示数字的值,数组的值代表出现的次数。
使用动态规划的方法来解决这个问题。建立一个dp[i][j] 表,i代表使用0-i之间的数构成子集,j是记录十个质数使用情况的int,状态转移式子分情况讨论:
如果i本身具有相同的质数,那么dp[i][j] = dp[i - 1][j];
如果i本身不具有相同的质数,那么dp[i][j] = dp[i -1][j] + dp[i -1][j ^ iFlag] * viCount[i] ;
其中iFlag是i所具有的质数状态,由于需要在子集中加入i,所以之前子集的元素不能出现i中的质数,即dp[i -1][j ^ iFlag]。
由于各个i中几乎不存在相关的联系,而j ^ iFlag 并且 j & iFlag肯定比 j 小,所以可以使用一维数组来压缩二维dp。
注意样本很大,所以运算后要及时取模。
代码展示
class Solution {
public:
int iNumMax = 30;
int iMod = 1000000007;
vector<int> viPrimes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
int numberOfGoodSubsets(vector<int>& nums) {
vector<int> viCount(iNumMax + 1, 0);
vector<int> dp(1 << viPrimes.size());
for(auto num:nums)
{
viCount[num]++;
} dp[0] = 1;
for(int i = 0; i < viCount[1]; i++)
{
dp[0] = dp[0] * 2 % iMod;
} for(int i = 2; i <= iNumMax; i++)
{
if(!viCount[i])
continue; int iFlags = 0;
bool bCheck = false;
for(int j = 0; j < viPrimes.size(); j++)
{
if(i % (viPrimes[j] * viPrimes[j]) == 0)
{
bCheck = true;
break;
}
if(i % viPrimes[j] == 0)
{
iFlags |= 1 << j;
}
}
if(bCheck)
continue; for(int j = (1 << viPrimes.size()) - 1; j > 0; j--)
{
if((iFlags & j) == iFlags)
{
dp[j] = (dp[j] + (long long)dp[j ^ iFlags] * viCount[i]) % iMod;
}
} }
int iRet = 0;
for(int i = 1; i < 1 << viPrimes.size(); i++)
{
iRet = (iRet + dp[i]) % iMod;
}
return iRet; }
};
运行结果
LeetCode-1994 好子集的数目的更多相关文章
- [Leetcode 78]求子集 Subset
[题目] Given a set of distinct integers, nums, return all possible subsets (the power set). Note: The ...
- [LeetCode] Subsets II 子集合之二
Given a collection of integers that might contain duplicates, S, return all possible subsets. Note: ...
- N个元素的集合划分成互斥的两个子集的数目
前面这是寒假听马士兵老师讲的时候积累的语录.......... 1.php是水果刀,java是菜刀,刀法比较多,一年的和三年的区别很大. 2.nanicat连接mysql出现10061是服务没开启,却 ...
- Leetcode题目78.子集(回溯-中等)
题目描述: 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: nums = [1,2,3] 输出: [ [3], [1] ...
- Leetcode 78题-子集
LeetCode 78 网上已经又很多解这题的博客了,在这只是我自己的解题思路和自己的代码: 先贴上原题: 我的思路: 我做题的喜欢在本子或别处做写几个示例,以此来总结规律:下图就是我从空数组到数组长 ...
- leetCode 78.Subsets (子集) 解题思路和方法
Given a set of distinct integers, nums, return all possible subsets. Note: Elements in a subset must ...
- 【LeetCode 90】子集 II
题目链接 [题解] 我们在枚举下一个要取哪个数字的时候. 如 1112233 for (int i = start;i<=n;i++) //其中start-1是上一次取的位置. 如果i>s ...
- [Leetcode 90]求含有重复数的子集 Subset II
[题目] Given a collection of integers that might contain duplicates, nums, return all possible subsets ...
- LeetCode:Subsets I II
求集合的所有子集问题 LeetCode:Subsets Given a set of distinct integers, S, return all possible subsets. Note: ...
- [Leetcode 40]组合数和II Combination Sum II
[题目] Given a collection of candidate numbers (candidates) and a target number (target), find all uni ...
随机推荐
- mooc上的简单题,(疑惑已解决)
如题,在简单不过的题,在自己编译器上试了很多例子,输出结果都对.但是oj不给过:(已解决) 统计指定单词出现的次数(10分) 题目内容:输入6个单词,查找第6个单词在前5个单词中出现的次数. 输入:6 ...
- hashlib加密模块 subprocess模块 logging日志模块
目录 hashlib加密模块 简介 hashlib使用流程 hashilb加密模块使用说明 明文绑定密文 密文长度不变 多次传入 密文不可解密原因 加盐处理(salt) 普通加盐 动态加盐 加密实际运 ...
- loadrunner11汉化时提示模块插件无法注册的解决方法
安装汉化程序时,关闭杀毒软件.
- js属性对象的hasOwnProperty( )方法,检测一个属性是否是对象的自有属性
hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键). 语法: obj.hasOwnProperty(prop) 参数: prop ...
- Python实验报告(第7章)
实验7:面向对象程序设计 一.实验目的和要求 1.了解面向对象的基本概念(对象.类.构造方法): 2.学会类的定义和使用: 3.掌握属性的创建和修改: 4.掌握继承的基本语法. 二.实验环境 软件版本 ...
- MongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(2)-Swagger框架集成
Swagger是什么? Swagger是一个规范且完整API文档管理框架,可以用于生成.描述和调用可视化的RESTful风格的 Web 服务.Swagger 的目标是对 REST API 定义一个标准 ...
- CentOS7.6搭建Hadoop2.7.2运行环境-三节点集群模式
一 环境准备 1. 准备机器 2. 修改静态IP 3. 修改主机名 4. 关闭防火墙 5. 创建普通用户hadoop 添加hadoop用户 [root@hadoop102 ...
- cookie、session,、token,还在傻傻分不清?
摘要:session 和 token 本质上是没有区别的,都是对用户身份的认证机制,只是他们实现的校验机制不一样而已. 本文分享自华为云社区<Session/Cookie/Token 还傻傻分不 ...
- &#127538;Eclipse通过jdbc连接数据库制作简单登陆界面【新手必看】
一.前言: 做网站开发,要求有多种搭配方式,前台技术可以使用PHP.ASP.JSP.ASP.NET.CGI等任何一种: 需要用到的基础语言用的最多的就是HTML/CSS.JS.JAVA.XML这些了, ...
- post方法易错地方
<body> <h1>登录</h1> <input type="text" placeholder="请输入用户名" ...