LeetCode 155. 掷骰子等于目标和的方法数:动态规划

【LetMeFly】1155.掷骰子等于目标和的方法数:动态规划

力扣题目链接:https://leetcode.cn/problems/number-of-dice-rolls-with-target-sum/

这里有 n 个一样的骰子,每个骰子上都有 k 个面,分别标号为 1k

给定三个整数 n , ktarget ,返回可能的方式(从总共kn种方式中)滚动骰子的数量,使正面朝上的数字之和等于target

答案可能很大,你需要对 109 + 7 取模

示例 1:

复制代码
输入:n = 1, k = 6, target = 3
输出:1
解释:你扔一个有 6 个面的骰子。
得到 3 的和只有一种方法。

示例 2:

复制代码
输入:n = 2, k = 6, target = 7
输出:6
解释:你扔两个骰子,每个骰子有 6 个面。
得到 7 的和有 6 种方法:1+6 2+5 3+4 4+3 5+2 6+1。

示例 3:

复制代码
输入:n = 30, k = 30, target = 500
输出:222616187
解释:返回的结果必须是对 109 + 7 取模。

提示:

  • 1 <= n, k <= 30
  • 1 <= target <= 1000

方法一:动态规划(DP)

开辟一个动态规划数组 d p dp dp,其中 d p [ i ] [ j ] dp[i][j] dp[i][j]代表 i i i个骰子的和为 j j j的方案数。

初始值 d p [ i ] [ j ] = 0 dp[i][j]=0 dp[i][j]=0,而 d p [ 1 ] [ 1 − k ] = 1 dp[1][1-k]=1 dp[1][1−k]=1。

这样,我们就可以从第二天开始枚举:

python 复制代码
for i from 2 to n:  # i个骰子
   for j from 1 to target:  # 和为j
       for _k from 1 to min(k, target):  # i个骰子和为j,可以由 i-1个骰子和为j-_k 加上 一个值为_k的骰子 得到
	       dp[i][j] = (dp[i][j] + dp[i - 1][j - _k]) % MOD

优化:

  1. 不难发现 i i i个骰子的状态只和 i − 1 i-1 i−1个骰子的状态有关,因此可以将二维数组压缩为一维。
  2. 我们初始化了1个骰子从1到k的方案数为1,其实我们也可以只领 d p [ 0 ] [ 0 ] = 1 dp[0][0]=1 dp[0][0]=1(0个骰子和为0的方案数为1)

复杂的分析

  • 时间复杂度 O ( n × k × t a r g e t ) O(n\times k\times target) O(n×k×target)
  • 空间复杂度 O ( n × t a r g e t ) O(n\times target) O(n×target)或 O ( t a r g e t ) O(target) O(target)

AC代码

C++

没有进行空间优化:

cpp 复制代码
typedef long long ll;
const ll MOD = 1e9 + 7;
class Solution {
public:
    int numRollsToTarget(int n, int k, int target) {
        vector<vector<ll>> dp(n + 1, vector<ll>(target + 1, 0));
        for (int j = 1; j <= min(k, target); j++) {
            dp[1][j] = 1;
        }
        for (int i = 2; i <= n; i++) {
            for (int j = 1; j <= target; j++) {
                for (int _k = 1; _k <= min(k, j); _k++) {
                    dp[i][j] = (dp[i][j] + dp[i - 1][j - _k]) % MOD;
                }
            }
        }
        return dp[n][target];
    }
};
Python

进行了空间优化:

python 复制代码
MOD = int(1e9 + 7)
class Solution:
    def numRollsToTarget(self, n: int, k: int, target: int) -> int:
        dp = [1] + [0] * target
        for i in range(1, n + 1):
            for j in range(target, -1, -1):
                dp[j] = 0
                for _k in range(1, min(k + 1, j + 1)):
                    dp[j] = (dp[j] + dp[j - _k]) % MOD
        return dp[-1]

同步发文于CSDN,原创不易,转载经作者同意后请附上原文链接哦~

Tisfy:https://letmefly.blog.csdn.net/article/details/134023955

相关推荐
workflower15 小时前
机器人应用-楼宇室内巡逻
大数据·人工智能·算法·microsoft·机器人·动态规划·享元模式
py有趣15 小时前
力扣热门100题之编辑距离
数据结构·算法·leetcode
贾斯汀玛尔斯16 小时前
每天学一个算法--动态规划(Dynamic Programming, DP)
算法·动态规划
水木流年追梦16 小时前
CodeTop 热门题目汇总hot300题
算法·leetcode·职场和发展
f3iiish16 小时前
2078. 两栋颜色不同且距离最远的房子 力扣
算法·leetcode
sheeta199818 小时前
LeetCode 每日一题笔记 日期:2026.04.21 题目:1722. 执行交换操作后的最小汉明距离
笔记·算法·leetcode
玛丽莲茼蒿19 小时前
Leetcode hot100 买卖股票的最佳时机【简单】
算法·leetcode·职场和发展
阿Y加油吧19 小时前
两道 LeetCode 题的复盘笔记:从「只会暴力」到「懂优化」
笔记·算法·leetcode
We་ct19 小时前
LeetCode 300. 最长递增子序列:两种解法从入门到优化
开发语言·前端·javascript·算法·leetcode·typescript
始三角龙20 小时前
LeetCode hoot 100 -- 找到字符串中的所有字母异位词
算法·leetcode·职场和发展