Leetcode 2902. Count of Sub-Multisets With Bounded Sum

本文介绍了如何解决LeetCode题目2902CountofSub-MultisetsWithBoundedSum,通过动态规划方法求解,作者分享了初始思路、Python代码实现及遇到的超时问题,最后提到大佬的优化方案,降低了时间复杂度和内存占用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 解题思路

这一题有点惭愧,因为没有搞定,遇上了超时问题……

我的思路其实还是挺直接的,就是直接使用动态规划,首先将元素按照unique number进行分组,然后分别考察其取用各个数目的情况下的可能情况。

由此,基本我们就转换成一个元素取用的动态规划问题,剩下的我们就只需要进行剪枝优化即可。

2. 代码实现

给出python代码实现如下:

class Solution:
    def countSubMultisets(self, nums: List[int], l: int, r: int) -> int:
        MOD = 10**9+7
        
        cnt = Counter(nums)
        nums = sorted(cnt.items(), reverse=True)
        n = len(nums)
        accums = [0 for _ in range(n+1)]
        for i in range(n-1, -1, -1):
            accums[i] = accums[i+1] + nums[i][0] * nums[i][1]
        
        @lru_cache(None)
        def dp(idx, prev):
            if idx >= n:
                return 1 if l <= prev <= r else 0
            if prev > r:
                return 0
            if prev + accums[idx] < l:
                return 0
            num, m = nums[idx]
            return sum(dp(idx+1, prev + i*num) for i in range(m+1)) % MOD
        
        return dp(0, 0)

不过很不幸的是,上述算法一直遇到超时问题,最后也没有优化掉这个问题……

3. 算法优化

看了一下大佬们的解答,整体依然还是动态规划的思路,而且也是需要先将数据按照unique number进行分组。

不过,大佬们的解法是直接按照所有的值进行动态规划,考察得到某个具体的值的情况下可能的选择方法。

给出大佬们的python代码实现如下:

class Solution:
    def countSubMultisets(self, nums: List[int], l: int, r: int) -> int:
        MOD = 10**9+7
        
        cnt = Counter(nums)
        dup = cnt[0] + 1
        nums = [(k, v) for k, v in cnt.items() if k != 0]

        dp = [0 for _ in range(r+1)]
        dp[0] = 1
        for num, k in nums:
            dp_acc = [0] * (num + r + 1)
            for i in range(r + 1):
                dp_acc[num+i] = dp_acc[i] + dp[i]
            new_dp = [0 for _ in range(r+1)]
            for i in range(r, -1, -1):
                new_dp[i] = (dp_acc[i + num] - dp_acc[max(0, i - k * num)]) % MOD
            dp = new_dp
        return (sum(dp[l:]) * dup) % MOD

提交代码评测得到:耗时4445ms,占用内存20.4MB。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值