Problem Statement:
You have n
 dice, and each dice has k
 faces numbered from 1
 to k
. Given three integers n
, k
, and target
, return the number of possible ways (out of the kn
 total ways) to roll the dice, so the sum of the face-up numbers equals target
. Since the answer may be too large, return it modulo 10^9 + 7
.
Example 1:
Input: n = 1, k = 6, target = 3 Output: 1 Explanation: You throw one die with 6 faces. There is only one way to get a sum of 3.
Example 2:
Input: n = 2, k = 6, target = 7 Output: 6 Explanation: You throw two dice, each with 6 faces. There are 6 ways to get a sum of 7: 1+6, 2+5, 3+4, 4+3, 5+2, 6+1.
Example 3:
Input: n = 30, k = 30, target = 500 Output: 222616187 Explanation: The answer must be returned modulo 109 + 7.
Constraints:
1 <= n, k <= 30
1 <= target <= 1000
Solution:
1.Recursion
class Solution {
public int numRollsToTarget(int n, int k, int target) {
int[] ans = new int[1];
int[][] dp = new int[n + 1][target + 1];
for(int[] row: dp){
Arrays.fill(row, -1);
}
numRollsToTargetHelper(n, k, target, ans, dp);
return ans[0];
}
public void numRollsToTargetHelper(int currDice, int k, int target, int[] ans, int[][] dp) {
if (currDice == 0) {
if (target == 0) {
ans[0] = (ans[0] + 1) % 1000000007;
dp[currDice][target] = ans[0];
}
return;
}
if (target < 0) {
return;
}
if(dp[currDice][target] != -1){
return;
}
for (int i = 1; i <= k; i++) {
numRollsToTargetHelper(currDice - 1, k, target - i, ans, dp);
}
}
}
2. Recursion and Memoization:
class Solution {
public int numRollsToTarget(int n, int k, int target) {
int[][] dp = new int[n + 1][target + 1];
for(int[] row: dp){
Arrays.fill(row, -1);
}
return numRollsToTargetHelper(n, k, target, dp);
}
public int numRollsToTargetHelper(int currDice, int k, int target, int[][] dp) {
if (currDice == 0) {
if (target == 0) {
return 1;
}
return 0;
}
if(target < 0){
return 0;
}
if (dp[currDice][target] != -1) {
return dp[currDice][target];
}
int ways = 0;
for (int i = 1; i <= k; i++) {
ways = (ways + numRollsToTargetHelper(currDice - 1, k, target - i, dp)) % 1000000007;
}
return dp[currDice][target] = ways;
}
}
3. Tabulation:
public int numRollsToTarget(int n, int k, int target) {
int[][] dp = new int[n + 1][target + 1];
dp[0][0] = 1; // There is one way to achieve a sum of 0 with 0 dice
int MOD = 1000000007;
for (int dice = 1; dice <= n; dice++) {
for (int t = 0; t <= target; t++) {
dp[dice][t] = 0; // Initialize current state
for (int face = 1; face <= k; face++) {
if (t - face >= 0) {
dp[dice][t] = (dp[dice][t] + dp[dice - 1][t - face]) % MOD;
}
}
}
}
return dp[n][target];
}
4. Space Optimized:
class Solution {
public int numRollsToTarget(int n, int k, int target) {
int[][] dp = new int[n + 1][target + 1];
int[] prev = new int[target + 1];
int[] curr = new int[target + 1];
prev[0] = 1;// There is one way to achieve a sum of 0 with 0 dice
int MOD = 1000000007;
for (int dice = 1; dice <= n; dice++) {
for (int t = 0; t <= target; t++) {
curr[t] = 0;
for (int face = 1; face <= k; face++) {
if (t - face >= 0) {
curr[t] = (curr[t] + prev[t - face]) % MOD;
}
}
}
prev = curr.clone();
}
return prev[target];
}
}