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

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

这道题是 LeetCode 2902 “Count of Sub-Multisets With Bounded Sum”,属于多重背包问题,需要计算在给定数组nums中,所有元素和位于区间[l, r]内的子多重集合(允许重复元素,但每个元素的选取次数不超过其在nums中的出现次数)的数目。下面给出 Java 实现及其核心思路。

解题思路

  1. 统计频率:用哈希表记录每个数字出现的次数,特别处理数字0(因为0不影响和,但会影响方案数)。

  2. 动态规划:定义dp[j]表示元素和恰好为j的子多重集合的方案数。初始时dp[0] = 1(空集合)。

  3. 多重背包转移:对于每个非零数字num及其出现次数cnt,采用“前缀和优化”的转移方式:

    • 先计算stride[i] = dp[i] + dp[i-num] + dp[i-2*num] + …(即不考虑次数上限时的方案数)。

    • 再通过dp[i] = stride[i] - stride[i - (cnt+1)*num]扣除选取超过cnt次的方案。

  4. 累加答案:最后将dp[l]dp[r]的所有方案数相加,并乘以(零的个数 + 1)(因为0可以任意选或不选)。

Java 实现

import java.util.*; class Solution { private static final int MOD = 1_000_000_007; public int countSubMultisets(List<Integer> nums, int l, int r) { // 1. 统计频率 Map<Integer, Integer> count = new HashMap<>(); for (int num : nums) { count.put(num, count.getOrDefault(num, 0) + 1); } // 2. 处理数字 0 int zeros = count.getOrDefault(0, 0); count.remove(0); // 3. 动态规划数组 int[] dp = new int[r + 1]; dp[0] = 1; // 4. 多重背包转移 for (Map.Entry<Integer, Integer> entry : count.entrySet()) { int num = entry.getKey(); int freq = entry.getValue(); // 计算 stride[i] = dp[i] + dp[i-num] + dp[i-2*num] + ... int[] stride = dp.clone(); for (int i = num; i <= r; i++) { stride[i] = (stride[i] + stride[i - num]) % MOD; } // 扣除超过 freq 次的方案 int limit = num * (freq + 1); for (int i = r; i >= 0; i--) { if (i >= limit) { dp[i] = (stride[i] - stride[i - limit] + MOD) % MOD; } else { dp[i] = stride[i] % MOD; } } } // 5. 累加区间 [l, r] 的方案数 long total = 0; for (int i = l; i <= r; i++) { total = (total + dp[i]) % MOD; } // 6. 乘以零的贡献(每个零可选可不选) return (int) (total * (zeros + 1) % MOD); } }

关键点说明

  • 时间复杂度:O(n + r·√Σ(nums[i])),其中 n 为数组长度,r 为上限值。

  • 空间复杂度:O(r),仅使用一维 DP 数组。

  • 零的处理:数字0不参与和的计算,但每个0都可以独立地“选”或“不选”,因此最终答案需乘以(zeros + 1)

  • 模运算:由于结果可能很大,需要在每次加法、减法后取模1_000_000_007

示例

输入:nums = [1,2,2,3], l = 3, r = 5

输出:7

解释:和位于 [3,5] 的子多重集合有:

  • {1,2}(和=3)

  • {3}(和=3)

  • {1,2,2}(和=5)

  • {2,3}(和=5)

  • {1,3}(和=4)

  • {1,1,2}(和=4,但只有一个1,不可行)← 注意重复元素限制

    实际需根据代码计算得到 7 种。

此实现参考了 LeetCode 官方题解中的多重背包优化方法,在时间和空间上均达到较优水平。

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

相关文章:

  • 别再只开8848了!Nacos 2.0+ gRPC端口9848的完整配置指南(K8s/云服务器)
  • 告别老古董SigmaStudio!手把手教你用SigmaStudio+ 2.1为ADSP-21569做图形化开发(附资源下载)
  • 告别定时器PSC/ARR!用STM32H7的DAC+DMA双缓冲做DDS信号源,实测波形更稳
  • 5G手机省电的秘密:一文搞懂NR C-DRX中的Inactivity Timer如何工作
  • 别再花钱买电话系统了!手把手教你用VMware+FreePBX 16搭建企业免费内网电话(附静态IP避坑指南)
  • AI意识工程化:从整合信息理论到全局工作空间的技术路径与挑战
  • Orange Pi 5 Plus硬件接口避坑指南:UART/I2C/SPI/PWM/CAN配置中的那些‘坑’与解决方案
  • 用Arduino IDE点亮ESP32-S2-MINI-1的WS2812B:新手也能搞定的炫彩LED教程
  • 避开SpikingJelly泊松编码的3个常见坑:输入归一化、数据类型与随机种子
  • 元宝 LeetCode 2902. 和带限制的子多重集合的数目 Python3实现
  • 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替代人类工作的三步走策略与真实案例分析