当前位置: 首页 > 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.gsyq.cn/news/1438436.html

相关文章:

  • 区块链+物联网构建环境价值互联网:机器自主交易绿电与碳资产
  • AMD SEV实战:在KVM/QEMU上快速搭建你的第一个机密虚拟机(含密钥管理避坑指南)
  • 构建面向AI的现代数据湖:从架构原则到硬件选型实战
  • AI Agent Harness冷启动优化:快速响应方案
  • 医疗设备安规入门:一张图搞懂BF型设备的MOOP/MOPP绝缘路径(附GB 9706.1附录解析)
  • 从布尔表达式到可综合代码:一个全加器的Verilog RTL设计完整流程(附代码规范检查清单)
  • 从DDR到DDR5:Burst和Prefetch的演变如何决定了内存性能的飞跃
  • DIY土壤湿度传感器:从腐蚀铜板到Arduino读取的完整指南
  • 量子策略评估(QPE)原理与强化学习应用
  • 别再只用if了!用np.all()和np.any()让你的NumPy数据清洗效率翻倍
  • Nacos 2.x 本地联调踩坑记:解决 gRPC 端口偏移导致的 StatusRuntimeException
  • 从呼吸到电能:DIY口罩发电项目详解与能量收集技术实践
  • 基于Arduino与步进/伺服电机的低成本物理开关自动化方案
  • AI时代人类转型:从执行者到策展人与教练的核心能力重构
  • AI营销实战指南:从用户画像到智能投放的完整落地路径
  • CRAFT框架:大模型驱动的多机器人协作训练方案
  • GPT模型技术本质与AGI鸿沟:从Transformer到通用人工智能的路径分析
  • 别再手动敲字了!用Python+Tesseract批量提取图片文字,5分钟搞定文档电子化
  • 量子信息流安全:SPO-QPN框架下的并发系统不透明性验证与策略强制执行
  • AI诗歌创作实验:从提示词工程到人机协作的实践指南
  • 用Python和PySAL搞定空间数据分析:手把手教你绘制乔治亚州教育不平等热点图
  • 别再对着真机发愁了!用华为eNSP从零搭建你的第一个企业网实验环境(附拓扑文件)
  • 2023年AR技术趋势:从空间计算到WebAR,12个实战方向深度解析
  • 避坑指南:STM32的PWM输入捕获模式,配置TIM3_CH1时这几个寄存器别设错
  • 别再手动发通知了!用ThinkPHP 6.x + uni-push 2.0 给你的UniApp APP做个自动消息推送服务
  • 2024年Intel OneAPI更新后,VASP 6.3.2安装避坑全记录(附常见错误解决方案)
  • CTF流量分析实战:从一道DNS题看Base64隐写与数据提取(Wireshark操作指南)
  • 不只是点云分割:拆解PMF论文里的多传感器融合思路,以及如何用SemanticKITTI API玩转可视化
  • 反哺RAG,SkillGraph把skill组装起来了
  • 告别Docker Hub抽风:手把手教你为群晖配置镜像加速与SSH拉取双保险