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];
}
}