githubEdit

07. Dice Throw

βœ… GFG solution to Dice Throw: count number of ways to get target sum using n dice with m faces using dynamic programming. πŸš€

The problem can be found at the following link: πŸ”— Question Linkarrow-up-right

🧩 Problem Description

Given n dice each with m faces, find the number of ways to get sum x which is the summation of values on each face when all the dice are thrown.

πŸ“˜ Examples

Example 1

Input: m = 6, n = 3, x = 12
Output: 25
Explanation: There are 25 total ways to get the sum 12 using 3 dice with faces from 1 to 6.

Example 2

Input: m = 2, n = 3, x = 6
Output: 1
Explanation: There is only 1 way to get the sum 6 using 3 dice with faces from 1 to 2. 
All the dice will have to land on 2.

Example 3

πŸ”’ Constraints

  • $1 \le m, n, x \le 50$

βœ… My Approach

The optimal solution uses Space-Optimized Dynamic Programming:

1D DP with Backward Iteration

  1. DP State Definition:

    • dp[j] = number of ways to get sum j using current number of dice.

    • Start with base case: dp[0] = 1 (one way to get sum 0 with 0 dice).

  2. Transition Logic:

    • For each die (1 to n), update all possible sums.

    • For each sum j, consider all possible face values (1 to m).

    • dp[j] = sum of dp[j-k] for all valid face values k.

  3. Backward Iteration:

    • Process sums from high to low to avoid overwriting values we still need.

    • This allows using single array instead of two arrays.

  4. Optimization:

    • Space: O(x) instead of O(n Γ— x) by reusing array.

    • After processing each die, reset dp[0] = 0 as we can't get sum 0 with dice.

Key Insight: The problem is similar to coin change but with constraints on minimum (1) and maximum (m) values per item (die).

πŸ“ Time and Auxiliary Space Complexity

  • Expected Time Complexity: O(n Γ— x Γ— m), where n is the number of dice, x is the target sum, and m is the number of faces per die. For each of n dice, we process x possible sums, and for each sum, we check m face values.

  • Expected Auxiliary Space Complexity: O(x), as we use a single 1D array of size x+1 to store the DP states, which is much more space-efficient than a 2D approach.

πŸ§‘β€πŸ’» Code (C++)

chevron-right⚑ View Alternative Approaches with Code and Analysishashtag

πŸ“Š 2️⃣ 2D DP Approach

πŸ’‘ Algorithm Steps:

  1. Create 2D array dp[i][j] where i = dice count, j = sum.

  2. Initialize base case: dp[0][0] = 1.

  3. For each die, calculate ways for each sum.

  4. Return dp[n][x].

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n Γ— x Γ— m) - Three nested loops

  • Auxiliary Space: πŸ’Ύ O(n Γ— x) - 2D array storage

βœ… Why This Approach?

  • Clear state representation

  • Easy to understand transitions

  • Good for learning DP concepts

πŸ“Š 3️⃣ Recursive with Memoization

πŸ’‘ Algorithm Steps:

  1. Define recursive function: ways(dice, sum).

  2. Base cases: dice=0 and sum=0 β†’ return 1, else 0.

  3. For each face value, recursively calculate ways.

  4. Use memoization to avoid recomputation.

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n Γ— x Γ— m) - With memoization

  • Auxiliary Space: πŸ’Ύ O(n Γ— x) - Recursion stack + memoization

βœ… Why This Approach?

  • Natural recursive thinking

  • Memoization prevents recomputation

  • Top-down approach easier for some

πŸ“Š 4️⃣ Optimized DP with Prefix Sum

πŸ’‘ Algorithm Steps:

  1. Use prefix sum to optimize inner loop.

  2. Instead of summing dp[j-1] to dp[j-m], use prefix difference.

  3. Maintain running sum for O(1) range sum queries.

  4. Update DP values efficiently.

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n Γ— x Γ— m) - Standard DP time

  • Auxiliary Space: πŸ’Ύ O(x) - Single extra array

βœ… Why This Approach?

  • Clean separation of dice iterations

  • Easy to understand state transitions

  • Good balance of clarity and efficiency

πŸ†š πŸ” Comparison of Approaches

πŸš€ Approach

⏱️ Time Complexity

πŸ’Ύ Space Complexity

βœ… Pros

⚠️ Cons

🎯 1D DP Backward

🟒 O(nΓ—xΓ—m)

🟒 O(x)

πŸš€ Most space efficient

πŸ”§ Backward iteration confusing

πŸ“Š 2D DP

🟒 O(nΓ—xΓ—m)

πŸ”΄ O(nΓ—x)

πŸ“– Clear state representation

πŸ’Ύ High space usage

πŸ”„ Memoization

🟒 O(nΓ—xΓ—m)

πŸ”΄ O(nΓ—x)

🎯 Natural recursion

πŸ”§ Stack overflow risk

πŸ“ˆ Optimized DP

🟒 O(nΓ—xΓ—m)

🟒 O(x)

⚑ Clean code structure

πŸ”§ Uses two arrays alternately

πŸ† Best Choice Recommendation

🎯 Scenario

πŸŽ–οΈ Recommended Approach

πŸ”₯ Performance Rating

πŸ… Space-constrained environment

πŸ₯‡ 1D DP Backward

β˜…β˜…β˜…β˜…β˜…

πŸ“– Learning DP concepts

πŸ₯ˆ 2D DP

β˜…β˜…β˜…β˜…β˜…

🎯 Prefer recursion

πŸ₯‰ Memoization

β˜…β˜…β˜…β˜…β˜†

πŸ”§ Code clarity

πŸ… Optimized DP

β˜…β˜…β˜…β˜…β˜†

β˜• Code (Java)

🐍 Code (Python)

🧠 Contribution and Support

For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: πŸ“¬ Any Questions?arrow-up-right. Let's make this learning journey more collaborative!

⭐ If you find this helpful, please give this repository a star! ⭐


πŸ“Visitor Count

Visitor counter

Last updated