【leetcode刷题第40天】1994.好子集的数目

2024-04-16 04:38

本文主要是介绍【leetcode刷题第40天】1994.好子集的数目,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

第四十天

1994 好子集的数目

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

  • 比方说,如果 nums = [1, 2, 3, 4]
    • [2, 3][1, 2, 3][1, 3] 子集,乘积分别 为 6 = 2*36 = 2*33 = 3
    • [1, 4][4] 不是 子集,因为乘积分别为 4 = 2*24 = 2*2

请你返回 nums 中不同的 子集的数目对 10^9 + 7 取余 的结果。

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

方法

使用状态压缩dp来处理这个问题,首先我们得明确以下几点:

  • 如果一个子集是好子集,那么我们对其中的每一个元素进行质因数分解,得到的最终结果就是 题目中要求的互不相同的质数的乘积。换言之,对于4,9..等数,他们的质因数分解存在两个或以上相同的质因子,则不可能存在于好子集中。
  • 对于1,其起到的作用可有可无,因为1和任何数相乘都不会发生变化,所以对于所有的1,其可取可不取,它的存在会使最终的结果翻 2 c o u n t [ 1 ] 2^{count[1]} 2count[1]倍。
  • 30以内的质数只有2,3,5,7,11,13,17,19,23,2910个,最极端的情况是这10个数都出现一次,对于其他情况,我们对好子集进行质因数分解,只要上述各个质数出现的次数不多于1次,就是一个合法的情况。我们使用一个长度为10的二进制数来表示各个质数出现的情况,对于状态status,其第i位上的1表示第i个质数出现了一次。

我们定义dp[i]表示以i作为状态码的好子集的数量,例如dp[1024]1024的二进制表示是1111111111,表示上述10个质数都出现了一次,它们所组成的乘积对应的好子集的数量。

考虑状态转移方程,对于一个数a,我们先预先统计出其出现的次数,然后将其转换为不同的质因数的积,将这些不同的质因数转换成一个subset,表示能够用这个数a能够引出来的状态。然后我们从a这个状态去转移,当一个status & subset = 0时,表明这个status能够由subset这个状态转移过来。

class Solution {public static final int MOD = 1000000007;public int numberOfGoodSubsets(int[] nums) {int[] primes = new int[]{2, 3, 5, 7, 11, 13, 17, 19, 23, 29};int[] quantityOfNumberI = new int[31];for (int i : nums) quantityOfNumberI[i]++;long[] dp = new long[(1 << primes.length) + 1];dp[0] = 1;for (int i = 2; i <= 30; ++i) {if (quantityOfNumberI[i] == 0) continue;int subset = 0;boolean isValid = true;for (int j = 0; j < primes.length; ++j) {if (i % (primes[j] * primes[j]) == 0) {isValid = false;break;}if (i % primes[j] == 0) subset |= (1 << j);}if (isValid) {for (int mask = 1; mask <= (1 << primes.length); ++mask) {if ((mask & subset) == subset)dp[mask] = (dp[mask] % MOD + ((dp[mask ^ subset] % MOD) * quantityOfNumberI[i]) % MOD) % MOD;}}}long res = 0;for (int i = 1; i < dp.length; ++i) res = (res % MOD + dp[i] % MOD) % MOD;for (int i = 0; i < quantityOfNumberI[1]; ++i) res = (res * 2) % MOD;return (int) res;}
}

这篇关于【leetcode刷题第40天】1994.好子集的数目的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/907802

相关文章

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

hdu1496(用hash思想统计数目)

作为一个刚学hash的孩子,感觉这道题目很不错,灵活的运用的数组的下标。 解题步骤:如果用常规方法解,那么时间复杂度为O(n^4),肯定会超时,然后参考了网上的解题方法,将等式分成两个部分,a*x1^2+b*x2^2和c*x3^2+d*x4^2, 各自作为数组的下标,如果两部分相加为0,则满足等式; 代码如下: #include<iostream>#include<algorithm

leetcode-24Swap Nodes in Pairs

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode swapPairs(L

leetcode-23Merge k Sorted Lists

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode mergeKLists

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

【JavaScript】LeetCode:16-20

文章目录 16 无重复字符的最长字串17 找到字符串中所有字母异位词18 和为K的子数组19 滑动窗口最大值20 最小覆盖字串 16 无重复字符的最长字串 滑动窗口 + 哈希表这里用哈希集合Set()实现。左指针i,右指针j,从头遍历数组,若j指针指向的元素不在set中,则加入该元素,否则更新结果res,删除集合中i指针指向的元素,进入下一轮循环。 /*** @param

【每日刷题】Day113

【每日刷题】Day113 🥕个人主页:开敲🍉 🔥所属专栏:每日刷题🍍 🌼文章目录🌼 1. 91. 解码方法 - 力扣(LeetCode) 2. LCR 098. 不同路径 - 力扣(LeetCode) 3. 63. 不同路径 II - 力扣(LeetCode) 1. 91. 解码方法 - 力扣(LeetCode) //思路:动态规划。 cl

LeetCode:64. 最大正方形 动态规划 时间复杂度O(nm)

64. 最大正方形 题目链接 题目描述 给定一个由 0 和 1 组成的二维矩阵,找出只包含 1 的最大正方形,并返回其面积。 示例1: 输入: 1 0 1 0 01 0 1 1 11 1 1 1 11 0 0 1 0输出: 4 示例2: 输入: 0 1 1 0 01 1 1 1 11 1 1 1 11 1 1 1 1输出: 9 解题思路 这道题的思路是使用动态规划