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

LeetCode 1223 投骰子模拟

骰子模拟器:基于动态规划的点数序列计数问题解析

一、题目背景

在骰子模拟的世界中,有一个特殊的骰子模拟器。它每次投掷时会生成一个 1 到 6 的随机数,但存在一个约束条件:连续掷出数字 i 的次数不能超过 rollMax[i]i 从 1 开始编号)。现在给定一个整数数组 rollMax 和整数 n,要求计算掷 n 次骰子可得到的不同点数序列的数量(答案需对 10^9 + 7 取模)。

二、解题思路分析

动态规划(DP)核心逻辑:将复杂问题拆解为子问题,通过记录子问题的解避免重复计算。

  1. 状态定义: 用三维数组 dp[i][j][k] 表示掷 i 次骰子,最后一次点数为 jj∈[0,5],对应 1-6 点),且 j 连续出现 k 次的序列数量。
  2. 初始化: 当 i = 1 时,每个点数首次出现的情况各 1 种,即 dp[1][j][1] = 1
  3. 状态转移
    • 情形一:当前点数首次连续出现(k = 1 dp[i][j][1] 可从前面任意非 j 的点数转移,即 dp[i][j][1] = Σ dp[i - 1][p][q]p≠j1≤q≤rollMax[p])。
    • 情形二:当前点数连续出现多次(k > 1 仅能从 dp[i - 1][j][k - 1] 转移,需满足 k ≤ rollMax[j]
  4. 结果计算: 遍历所有 dp[n][j][k]1≤k≤rollMax[j])求和并取模。
三、代码实现与详解
class Solution {
    private static final int MOD = (int) (1e9 + 7);
    public int dieSimulator(int n, int[] rollMax) {
        int[][][] dp = new int[n + 1][6][16];
        // 初始化:第一次投掷,每个点数出现1次的情况
        for (int j = 0; j < 6; j++) {
            dp[1][j][1] = 1;
        }
        // 动态规划:从第2次投掷开始计算
        for (int i = 2; i <= n; i++) {
            for (int j = 0; j < 6; j++) {
                // 情形一:当前点数首次连续出现
                for (int p = 0; p < 6; p++) {
                    if (p != j) {
                        for (int q = 1; q <= rollMax[p]; q++) {
                            dp[i][j][1] = (dp[i][j][1] + dp[i - 1][p][q]) % MOD;
                        }
                    }
                }
                // 情形二:当前点数连续出现多次
                for (int k = 2; k <= rollMax[j]; k++) {
                    dp[i][j][k] = dp[i - 1][j][k - 1];
                }
            }
        }
        // 计算最终结果:汇总所有有效状态
        int result = 0;
        for (int j = 0; j < 6; j++) {
            for (int k = 1; k <= rollMax[j]; k++) {
                result = (result + dp[n][j][k]) % MOD;
            }
        }
        return result;
    }
}

代码说明

  • 用 MOD 常量处理取模,dp 数组存储状态;
  • 三层循环实现状态转移,内层分别处理两种情形;
  • 最后两层循环累加 n 次投掷后的有效状态。
四、复杂度分析
  • 时间复杂度O(n\times 6^{2}\times 15)(假设 rollMax 最大值为 15);
  • 空间复杂度O(n\times 6\times 15),取决于 dp 数组大小。
五、总结

通过动态规划,我们以状态转移精准解决了骰子序列计数问题。关键在于定义状态、拆解情形并严格取模。若对细节有疑问,欢迎随时交流!

相关文章:

  • 安卓AssetManager【一】-资源的查找过程
  • 从MySQL快速上手数据仓库Hive
  • 论文阅读笔记——Multi-Token Attention
  • 华为机试—最大最小路
  • 为什么在删除数据库存在‘if exists‘语句
  • 判断两个 IP 地址是否在同一子网 C
  • Redis实现分布式定时任务
  • 畅游Diffusion数字人(23):字节最新表情+动作模仿视频生成DreamActor-M1
  • dfs和bfs算法
  • PyTorch DataLoader 参数详解
  • Autoware源码总结
  • 路由策略/策略路由之Filter-Policy
  • 基础层数据从kafka读取写入hbase的优化方案
  • 摄像头解析
  • 第一期:[特殊字符] 深入理解MyBatis[特殊字符]从JDBC到MyBatis——持久层开发的转折点[特殊字符]
  • Vue 3 和 Vue 2 的区别及优点
  • Flask+Plotly结合动态加载图形页面实践
  • cluster、update、delete在死元组清理上的作用
  • boss zp_stoken补环境
  • TQ15EG开发板教程:AD9361观测adc采集波形
  • 卖书的网站怎么做/百度问答seo
  • 专业集团网站建设/巨量关键词搜索查询
  • wordpress主题知言/seo下拉优化
  • 天津网站建设工作室/google应用商店
  • 项目管理软件的作用/seo网络营销案例分析
  • 惠州市人民政府门户网站/网络广告推广方法