[leetcode 周赛 149] 1155 掷骰子的N种方法

Posted slowbirdoflsh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[leetcode 周赛 149] 1155 掷骰子的N种方法相关的知识,希望对你有一定的参考价值。

1155 Number of Dice Rolls With Target Sum 掷骰子的N种方法

描述

这里有 d 个一样的骰子,每个骰子上都有 f 个面,分别标号为 1, 2, ..., f
我们约定:掷骰子的得到总点数为各骰子面朝上的数字的总和
如果需要掷出的总点数为 target,请你计算出有多少种不同的组合情况(所有的组合情况总共有f^d 种),模10^9 + 7后返回。

  • 示例 1:

    输入:d = 1, f = 6, target = 3
    输出:1

  • 示例 2:

    输入:d = 2, f = 6, target = 7
    输出:6

  • 示例 3:

    输入:d = 2, f = 5, target = 10
    输出:1

  • 示例 4:

    输入:d = 1, f = 2, target = 3
    输出:0

  • 示例 5:

    输入:d = 30, f = 30, target = 500
    输出:222616187

  • 提示:
    1 <= d, f <= 30
    1 <= target <= 1000

思路

这明显是个动态规划问题

  • 规律公式
    技术图片

d为骰子数, f为骰子面数, target为目标值, k表示当前第d个骰子掷出的数

  • 初始状态
    技术图片

需要投掷的目标数在单个骰子的范围内 返回1, 否则返回0

代码实现

技术图片

递归实现

class Solution 
    static int MOD = (int)(1e9+7);
    
    public int numRollsToTarget(int d, int f, int target) 
        if (target < d | target > d*f) return 0;
        
        int[][] dp = new int[d+1][target+1];
        // 初始化 全-1 表示未被处理
        for (int[] dpi : dp) Arrays.fill(dpi, -1);
        
        return helper(d, f, target, dp);
    
    
    int helper(int d, int f, int target, int[][] dp) 
        // target 超出骰子的投掷范围
        if (target < d | target > d*f) return 0;
        // 如果已经处理过 使用之前记录数据
        if (dp[d][target] != -1) return dp[d][target];
        // 当单个骰子时
        if (d==1) 
            if (target <= f && target > 0) return dp[d][target]=1;
            else return dp[d][target]=0;
        
        // 数据没有被记录 骰子数大于等于2
        int ans = 0;
        // 对当前骰子投掷出的每个面数都进行处理
        for (int cur=1; cur <= f; cur++) 
            ans = (ans + helper(d-1, f, target-cur, dp))%MOD;
        
        // 对数据进行记录
        return dp[d][target]=ans;
    

技术图片

非递归实现

class Solution 
    // 取模数 1e9 + 7
    final static int MOD = 1000000007;
    public int numRollsToTarget(int d, int f, int target) 
        if (target < d | target > d*f) return 0;
        
        // dp 表示当骰子为i(1~d)时j(1~target)的组合数
        // 其实长度可以是2 因为只使用上一轮的数据
        int[][] dp = new int[d+1][target+1];
        
        // 初始为1
        dp[0][0] = 1;
        // 从有1个骰子开始 1~d
        for (int i = 1; i <= d; i++) 
            // 当前骰子投掷数 1~f
            for (int cur = 1; cur <= f; cur++) 
                // 加上上一轮没有投掷cur时prev的组合数
                for (int prev = 0; prev+cur <= target; prev++) 
                    dp[i][prev+cur] = (dp[i][prev+cur] + dp[i-1][prev])%MOD;
                
            
        
        
        return dp[d][target];
    

以上是关于[leetcode 周赛 149] 1155 掷骰子的N种方法的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 1155. Number of Dice Rolls With Target Sum

我也是LeetCode周赛“三道题选手”啦 第270场周赛

LeetCode周赛第 291 场周赛(Go语言实现版)

LeetCode周赛第193场周赛

LeetCode周赛第194场周赛

LeetCode周赛第195场周赛