题目链接
题目描述
将一个骰子投掷 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;
}
}