【剑指offer】80.骰子的点数

题目链接

acwing

题目描述

将一个骰子投掷 n 次,获得的总点数为 s,s的可能范围为 n∼6n。

掷出某一点数,可能有多种掷法,例如投掷 2次,掷出 3点,共有 [1,2],[2,1] 两种掷法。

请求出投掷 n 次,掷出 n∼6n 点分别有多少种掷法。

数据范围:1≤n≤10

样例:

输入:n=1

输出:[1, 1, 1, 1, 1, 1]

解释:投掷1次,可能出现的点数为1-6,共计6种。每种点数都只有1种掷法。所以输出[1, 1, 1, 1, 1, 1]。

样例2

输入:n=2

输出:[1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]

解释:投掷2次,可能出现的点数为2-12,共计11种。每种点数可能掷法数目分别为1,2,3,4,5,6,5,4,3,2,1。
所以输出[1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]

题目分析

  • 考察的是dp数组
  • 一个二维数组:dp[n + 1][6*n + 1],代表投i次,点数总和为j的投掷方式
  • 这一次的投掷方式是上一次决定的,所以从上往下遍历
  • 初始化:第一次投掷,1——6点数 投掷出来的 总方式为1
    • 另一种初始化方式 dp[0][0]设置为1即可
  • 第i轮投掷到点数j的总方式:第i-1轮投掷到(j-1——j-6)的方式之和
    • 上次数值差1-6,都有可能这次达到目标数值

代码实现

class Solution {
    public int[] numberOfDice(int n) {
        // 投i次,点数为j
        int[][] dp = new int[n + 1][6*n + 1];
        
        // 投1次,点数为j均为1
        for(int j = 1; j <= 6; j ++){
            dp[1][j] = 1;
        }
        
        for(int i = 2; i <= n; i ++){
            for(int j = i; j <= 6 * i; j ++){
                // 上次数值差1-6,都有可能这次达到目标数值
                for(int k = 1; k <= 6 && j - k >= 0; k ++){
                    dp[i][j] += dp[i - 1][j - k];   
                }
            }
        }
        
        
        // 共有6n-n+1种方式
        int[] res = new int[6*n-n+1];
        int count = 0;
        for(int j = n; j <= 6*n; j ++){
            res[count] = dp[n][j];
            count++;
        }
        return res;
    }
}

另一种初始化方式

class Solution {
    public int[] numberOfDice(int n) {
        // 投i次,点数为j
        int[][] dp = new int[n + 1][6*n + 1];
        
        dp[0][0] = 1;
        
        for(int i = 1; i <= n; i ++){
            for(int j = i; j <= 6 * i; j ++){
                // 上次数值差1-6,都有可能这次达到目标数值
                for(int k = 1; k <= 6 && j - k >= 0; k ++){
                    dp[i][j] += dp[i - 1][j - k];   
                }
            }
        }
        
        
        // 共有6n-n+1种方式
        int[] res = new int[6*n-n+1];
        int count = 0;
        for(int j = n; j <= 6*n; j ++){
            res[count] = dp[n][j];
            count++;
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值