|
| 1 | +package com.cheehwatang.leetcode; |
| 2 | + |
| 3 | +import java.util.Arrays; |
| 4 | + |
| 5 | +// Time Complexity : O(n * k), |
| 6 | +// where 'n' and 'k' are the variables used by the method. |
| 7 | +// For every face, we check every dice, to find all the possible combinations that sums to 'target', |
| 8 | +// thus we can treat it like nested for-loop. |
| 9 | +// |
| 10 | +// Space Complexity : O(n * target), |
| 11 | +// where 'n' and 'target' are the variables used by the method. |
| 12 | +// We use a matrix of 'n' rows with 'target' columns for memoization. |
| 13 | +// The recursive call stack has a maximum height of 'n'. |
| 14 | + |
| 15 | +public class NumberOfDiceRollsWithTargetSum_Memoization { |
| 16 | + |
| 17 | + // Approach: |
| 18 | + // A dynamic programming problem where there are overlapping subproblem, |
| 19 | + // for which each roll has possible 1 to k number face-up. |
| 20 | + // Here, the recursive and memoization method is used. |
| 21 | + // By reducing the target by the face-up number each roll (hence n - 1), |
| 22 | + // the successful sequence of rolls is achieved when n = 0 and target = 0, |
| 23 | + // which forms the base case where target == 0 && n == 0. |
| 24 | + // If target <= 0 || n == 0, meaning the sequence is unsuccessful. |
| 25 | + |
| 26 | + // Wrapper method to initiate the memo and call the recursive method. |
| 27 | + // As the number 0 in the memo is a meaningful result, set all the elements of the memo to -1. |
| 28 | + public int numRollsToTarget(int n, int k, int target) { |
| 29 | + // As the array is 0-indexed, we need + 1 length to accommodate 'n' and 'target' respectively. |
| 30 | + int[][] memo = new int[n + 1][target + 1]; |
| 31 | + for (int[] row : memo) Arrays.fill(row, -1); |
| 32 | + return numRollsToTarget(n, k, target, memo); |
| 33 | + } |
| 34 | + |
| 35 | + // Recursive method. |
| 36 | + private int numRollsToTarget(int n, int k, int target, int[][] memo) { |
| 37 | + // Base case for successful sequence. |
| 38 | + if (target == 0 && n == 0) return 1; |
| 39 | + // Base case for unsuccessful sequence. |
| 40 | + if (target <= 0 || n == 0) return 0; |
| 41 | + // If memo already contains the result, return the result. |
| 42 | + if (memo[n][target] != -1) return memo[n][target]; |
| 43 | + int modulus = (int) (1e9 + 7); |
| 44 | + int count = 0; |
| 45 | + // For each face, reduce the 'n' by 1 and 'target' by the face-up number. |
| 46 | + for (int face = 1; face <= k; face++) { |
| 47 | + count = (count + numRollsToTarget(n - 1, k, target - face, memo)) % modulus; |
| 48 | + } |
| 49 | + // Store the result into the memo and return the result. |
| 50 | + return memo[n][target] = count; |
| 51 | + } |
| 52 | +} |
0 commit comments