Dice Roll Simulation
HARDDescription
A die simulator generates a random number from 1 to 6 for each roll. You introduced a constraint to the generator such that it cannot roll the number i more than rollMax[i] (1-indexed) consecutive times.
Given an array of integers rollMax and an integer n, return the number of distinct sequences that can be obtained with exact n rolls. Since the answer may be too large, return it modulo 109 + 7.
Two sequences are considered different if at least one element differs from each other.
Example 1:
Input: n = 2, rollMax = [1,1,2,2,2,3] Output: 34 Explanation: There will be 2 rolls of die, if there are no constraints on the die, there are 6 * 6 = 36 possible combinations. In this case, looking at rollMax array, the numbers 1 and 2 appear at most once consecutively, therefore sequences (1,1) and (2,2) cannot occur, so the final answer is 36-2 = 34.
Example 2:
Input: n = 2, rollMax = [1,1,1,1,1,1] Output: 30
Example 3:
Input: n = 3, rollMax = [1,1,1,2,2,3] Output: 181
Constraints:
1 <= n <= 5000rollMax.length == 61 <= rollMax[i] <= 15
Approaches
Checkout 4 different approaches to solve Dice Roll Simulation. Click on different approaches to view the approach and algorithm in detail.
2D Dynamic Programming with Subtraction
This is a more efficient approach that redefines the DP state to reduce the dimensions of the table and improve the time complexity. Instead of tracking the consecutive count explicitly in the state, we calculate the number of valid sequences by taking the total possible sequences and subtracting the invalid ones. This 'subtraction' principle leads to a faster solution.
Algorithm
- Define
dp[i][j]as the number of valid sequences of lengthiending with facej. - Define
S[i]as the total number of valid sequences of lengthi, which issum(dp[i][p])over all facesp. - Base case:
S[0] = 1(for the empty sequence). - Iterate
ifrom 1 ton:- For each face
jfrom 0 to 5:- Start with
dp[i][j] = S[i-1], which is the count if there were no constraints. - Let
k = rollMax[j]. We must subtract the invalid sequences that end with more thankconsecutivej's. - If
i > k, the number of invalid sequences is the number of valid sequences of lengthi-k-1that did not end inj. This isS[i-k-1] - dp[i-k-1][j]. Subtract this fromdp[i][j]. - If
i == k, there is exactly one invalid sequence (allj's). Subtract 1.
- Start with
- Calculate
S[i]by summingdp[i][j]over allj.
- For each face
- Return
S[n].
Let dp[i][j] be the number of valid sequences of length i ending with face j. Let S[i] be the total number of valid sequences of length i.
To calculate dp[i][j], we can start with the total number of ways to form a sequence of length i-1 (S[i-1]) and append j. This gives us S[i-1] potential sequences.
However, this includes invalid sequences where j is rolled more than rollMax[j] consecutive times. We must subtract these. An invalid sequence of length i ending with rollMax[j] + 1 consecutive j's must have the form ... p j j ... j, where p != j. The prefix ... p has length i - (rollMax[j] + 1). The number of such prefixes is the number of valid sequences of that length that do not end in j, which is S[i - rollMax[j] - 1] - dp[i - rollMax[j] - 1][j]. This gives us our recurrence.
class Solution {
public int dieSimulator(int n, int[] rollMax) {
long MOD = 1_000_000_007;
long[][] dp = new long[n + 1][6];
long[] sum = new long[n + 1];
sum[0] = 1;
for (int i = 1; i <= n; i++) {
long currentSum = 0;
for (int j = 0; j < 6; j++) {
// Initially, assume we can append j to any valid sequence of length i-1
dp[i][j] = sum[i - 1];
int k = rollMax[j];
if (i > k) {
// Subtract sequences of length i-k-1 not ending with j
long toSubtract = (sum[i - k - 1] - dp[i - k - 1][j] + MOD) % MOD;
dp[i][j] = (dp[i][j] - toSubtract + MOD) % MOD;
} else if (i == k) {
// Subtract the sequence of all j's
dp[i][j] = (dp[i][j] - 1 + MOD) % MOD;
}
currentSum = (currentSum + dp[i][j]) % MOD;
}
sum[i] = currentSum;
}
return (int) sum[n];
}
}
Complexity Analysis
Pros and Cons
- Much faster time complexity than the 3D DP approaches.
- The DP state is simpler (2D vs 3D).
- Still uses linear space with respect to
n. - The recurrence relation is slightly more complex to derive.
Code Solutions
Checking out 3 solutions in different languages for Dice Roll Simulation. Click on different languages to view the code.
class Solution {
private
Integer[][][] f;
private
int[] rollMax;
public
int dieSimulator(int n, int[] rollMax) {
f = new Integer[n][7][16];
this.rollMax = rollMax;
return dfs(0, 0, 0);
}
private
int dfs(int i, int j, int x) {
if (i >= f.length) {
return 1;
}
if (f[i][j][x] != null) {
return f[i][j][x];
}
long ans = 0;
for (int k = 1; k <= 6; ++k) {
if (k != j) {
ans += dfs(i + 1, k, 1);
} else if (x < rollMax[j - 1]) {
ans += dfs(i + 1, j, x + 1);
}
}
ans %= 1000000007;
return f[i][j][x] = (int)ans;
}
}
Video Solution
Watch the video walkthrough for Dice Roll Simulation
Similar Questions
5 related questions you might find useful
Patterns:
Data Structures:
Companies:
Subscribe to Scale Engineer newsletter
Learn about System Design, Software Engineering, and interview experiences every week.
No spam, unsubscribe at any time.