当前位置: 首页 > news >正文

元宝 LeetCode 2902. 和带限制的子多重集合的数目 Python3实现

以下是 LeetCode 2902 题"和带限制的子多重集合的数目"的 Python3 实现代码。这个解决方案使用动态规划和多重背包优化技术,时间复杂度为 O(n + r·√Σ(nums[i])),其中 n 是数组长度,r 是上限值。

from typing import List
from collections import Counter

class Solution:
def countSubMultisets(self, nums: List[int], l: int, r: int) -> int:
MOD = 1_000_000_007

# 1. 统计频率
counter = Counter(nums)

# 2. 处理数字0
zeros = counter.get(0, 0)
if 0 in counter:
del counter[0]

# 3. 动态规划数组
dp = [0] * (r + 1)
dp[0] = 1

# 4. 多重背包转移
for num, freq in counter.items():
# 如果数字大于r,可以跳过
if num > r:
continue

# 计算前缀和
prefix = dp[:] # 复制当前dp数组

# 计算不考虑次数限制的前缀和
for i in range(num, r + 1):
prefix[i] = (prefix[i] + prefix[i - num]) % MOD

# 更新dp,扣除超过freq次的方案
limit = num * (freq + 1)
for i in range(r, -1, -1):
if i >= limit:
dp[i] = (prefix[i] - prefix[i - limit]) % MOD
else:
dp[i] = prefix[i] % MOD

# 5. 累加区间[l, r]的方案数
result = 0
for i in range(l, r + 1):
result = (result + dp[i]) % MOD

# 6. 乘以0的贡献(每个0可选可不选)
return (result * (zeros + 1)) % MOD


# 测试用例
def test_solution():
solution = Solution()

# 测试用例1
nums1 = [1, 2, 2, 3]
l1, r1 = 3, 5
result1 = solution.countSubMultisets(nums1, l1, r1)
print(f"测试用例1: nums={nums1}, l={l1}, r={r1}")
print(f"结果: {result1}")
print()

# 测试用例2
nums2 = [0, 0, 1, 2, 3]
l2, r2 = 1, 3
result2 = solution.countSubMultisets(nums2, l2, r2)
print(f"测试用例2: nums={nums2}, l={l2}, r={r2}")
print(f"结果: {result2}")
print()

# 测试用例3
nums3 = [1, 1, 1, 1]
l3, r3 = 2, 3
result3 = solution.countSubMultisets(nums3, l3, r3)
print(f"测试用例3: nums={nums3}, l={l3}, r={r3}")
print(f"结果: {result3}")
print()

# 测试用例4
nums4 = [2, 3, 5]
l4, r4 = 5, 5
result4 = solution.countSubMultisets(nums4, l4, r4)
print(f"测试用例4: nums={nums4}, l={l4}, r={r4}")
print(f"结果: {result4}")
print()

# 测试用例5: 空集
nums5 = [1, 2, 3]
l5, r5 = 0, 0
result5 = solution.countSubMultisets(nums5, l5, r5)
print(f"测试用例5: nums={nums5}, l={l5}, r={r5}")
print(f"结果: {result5}")


if __name__ == "__main__":
test_solution()

关键点说明

  1. 算法思路

    • 使用多重背包的动态规划方法

    • 通过前缀和优化将时间复杂度从 O(n×r×cnt) 降低到 O(n×r)

    • 特殊处理数字0,因为它不影响和但影响方案数

  2. 核心步骤

    • 统计每个数字的出现频率

    • 处理数字0,因为0可以选择任意多个,但不会增加和

    • 使用动态规划计算每个可能的和的方案数

    • 对每个数字使用前缀和技巧优化多重背包转移

    • 最后累加[l, r]区间内的方案数,并乘以0的贡献

  3. 时间复杂度

    • 主要部分:O(r × 不同数字的个数)

    • 当r=2×10⁴时,这是可接受的

  4. 空间复杂度

    • O(r),使用一维DP数组

    • 额外使用O(n)的空间存储频率统计

  5. 边界情况处理

    • 处理数字0的情况

    • 处理数字大于r的情况(可以直接跳过)

    • 处理空集合的情况(和为0)

这个实现能够高效地计算满足条件的子多重集合的数目,并正确处理各种边界情况。

http://www.jsqmd.com/news/927104/

相关文章:

  • WRF-CHEM生物排放处理避坑指南:从MEGAN数据下载到编译运行,手把手解决gfortran版本冲突
  • AI诗歌与说唱创作实验:人机协作的边界、潜力与实战指南
  • 用VOFA+上位机给HC08蓝牙模块改名、配对、改波特率,保姆级图文教程(附AT指令表)
  • 从Turtlesim到真实项目:ROS2 Humble常用命令实战避坑指南(含录包、参数调试)
  • 一根网线搞定树莓派SSH:无显示器、无路由器,用Windows笔记本直连的保姆级教程
  • ExT框架:基于Transformer的自主挖掘机智能控制系统
  • PHPGraphQLAPI实现与最佳实践
  • 机器学习驱动的数据清洗:从规则到智能的范式转变与实践指南
  • 《数据库原理》精要解读(八、九、十)—— 事务、恢复与并发:数据库内核的三大支柱
  • 区块链+物联网构建环境价值互联网:机器自主交易绿电与碳资产
  • 面试官最爱问的Python八股文,我用这18个知识点帮你一次性理清(附避坑指南)
  • AMD SEV实战:在KVM/QEMU上快速搭建你的第一个机密虚拟机(含密钥管理避坑指南)
  • 基于深度学习的yolov8仪器仪表识别 数字表压力表读数 温度计读数 电压表读数图像识别系统设计
  • 别再手动算时间差了!用Ant Design Vue的a-table组件,5分钟搞定表格日期列差值展示
  • 学生选课微信小程序全栈开发包(含SSM后台源码、MySQL建表脚本与部署说明)
  • 构建面向AI的现代数据湖:从架构原则到硬件选型实战
  • 基于打字模式的用户身份验证:从行为生物识别到AI驱动的持续安全防线
  • 用影子模式测试新版 Harness 逻辑
  • AI Agent Harness冷启动优化:快速响应方案
  • AI替代人类工作的三步走策略与真实案例分析
  • 医疗设备安规入门:一张图搞懂BF型设备的MOOP/MOPP绝缘路径(附GB 9706.1附录解析)
  • 从布尔表达式到可综合代码:一个全加器的Verilog RTL设计完整流程(附代码规范检查清单)
  • 从DDR到DDR5:Burst和Prefetch的演变如何决定了内存性能的飞跃
  • 【读书笔记】《架构即未来》精华解读
  • DIY土壤湿度传感器:从腐蚀铜板到Arduino读取的完整指南
  • AI驱动招聘自动化:四大核心场景与成本效益深度解析
  • 避坑指南:逆向同花顺问财hexin-v时,你可能遇到的3个环境检测与反调试问题
  • 保姆级教程:用Python和nuscenes-devkit从零玩转nuScenes自动驾驶数据集(附完整代码)
  • 别只当备份用!解锁PostgreSQL逻辑复制的5个高阶玩法:从CDC到微服务数据分发
  • 【分享】微恢复助手 照片快速恢复 安全不泄露超好用