Talentd
FleetCode
Make and follow sheets.Sign in

Zuma Game solution and explanation

HardBreadth-First SearchDynamic ProgrammingMemoizationStack8 min read29.4% acceptanceUpdated 9 Apr 2026
花花酱 LeetCode 488. Zuma Game - 刷题找工作 EP84Hua Hua · 15:19 · 4K viewsWatch on YouTube
5 more videos on this problem
  1. 花花酱 LeetCode 488. Zuma Game - 刷题找工作 EP84Hua Hua · 15:19 · 4K views
  2. 488. Zuma Game (Leetcode Hard)Programming Live with Larry · 1:09:23 · 3K views
  3. Leetcode 0488. Zuma GameFearless Learner · 31:25 · 1K views
  4. LeetCode 488: Zuma GameAlitaCode · 31:52 · 344 views
  5. No Sound Leetcode 488: Zuma GameExtremeProgrammer · 4:53 · 113 views
  6. Chatgpt C++ leetcode 488. Zuma GameWindows 8.1 Tails Prower Ultra · 13:49 · 17 views

The problem

You are playing a variation of the game Zuma.

In this variation of Zuma, there is a single row of colored balls on a board, where each ball can be colored red 'R', yellow 'Y', blue 'B', green 'G', or white 'W'. You also have several colored balls in your hand.

Your goal is to clear all of the balls from the board. On each turn:

  • Pick any ball from your hand and insert it in between two balls in the row or on either end of the row.
  • If there is a group of three or more consecutive balls of the same color, remove the group of balls from the board.
    • If this removal causes more groups of three or more of the same color to form, then continue removing each group until there are none left.
  • If there are no more balls on the board, then you win the game.
  • Repeat this process until you either win or do not have any more balls in your hand.

Given a string board, representing the row of balls on the board, and a string hand, representing the balls in your hand, return the minimum number of balls you have to insert to clear all the balls from the board. If you cannot clear all the balls from the board using the balls in your hand, return -1.

Example 1:

Input: board = "WRRBBW", hand = "RB"
Output: -1
Explanation: It is impossible to clear all the balls. The best you can do is:
- Insert 'R' so the board becomes WRRRBBW. WRRRBBW -> WBBW.
- Insert 'B' so the board becomes WBBBW. WBBBW -> WW.
There are still balls remaining on the board, and you are out of balls to insert.

Example 2:

Input: board = "WWRRBBWW", hand = "WRBRW"
Output: 2
Explanation: To make the board empty:
- Insert 'R' so the board becomes WWRRRBBWW. WWRRRBBWW -> WWBBWW.
- Insert 'B' so the board becomes WWBBBWW. WWBBBWW -> WWWW -> empty.
2 balls from your hand were needed to clear the board.

Example 3:

Input: board = "G", hand = "GGGGG"
Output: 2
Explanation: To make the board empty:
- Insert 'G' so the board becomes GG.
- Insert 'G' so the board becomes GGG. GGG -> empty.
2 balls from your hand were needed to clear the board.

Constraints:

  • 1 <= board.length <= 16
  • 1 <= hand.length <= 5
  • board and hand consist of the characters 'R', 'Y', 'B', 'G', and 'W'.
  • The initial row of balls on the board will not have any groups of three or more consecutive balls of the same color.

Approach overview

Problem Overview: You are given a board string representing colored balls and a hand containing extra balls. Insert balls anywhere on the board so that whenever three or more consecutive balls of the same color appear, they disappear and may trigger chain reactions. The goal is to clear the entire board using the minimum number of insertions.

Approach 1: Backtracking with DFS + Memoization (Time: O(b^h * n), Space: O(b^h))

This problem is naturally modeled as a recursive search. At every step, try inserting a ball from the hand into every possible position on the board. After each insertion, simulate removals by repeatedly collapsing sequences of length ≥3 using a stack-like elimination pass. The recursion continues with the updated board and remaining hand until the board becomes empty. Because many board-hand combinations repeat, memoization caches states like (board, handCount) to avoid recomputation. This drastically prunes the search space and makes the solution practical even though the theoretical complexity is exponential.

The key insight is that only insertions that can help form or extend groups are useful. Pruning invalid placements and normalizing the board after every insertion keeps the state small. This approach heavily relies on string manipulation and memoization to explore the state space efficiently.

Approach 2: Greedy Iteration for Partial Progress (Time: O(n^2 * k), Space: O(n))

A simpler heuristic approach repeatedly scans the board looking for places where inserting a ball can immediately create or extend a group of three. For example, if the board has RR and the hand contains R, inserting it removes the group instantly. After each insertion, perform a collapse pass that removes any chain reactions. This strategy iterates until no more progress is possible or the board clears.

This method is easier to implement but does not explore all states, so it may miss the optimal sequence in tricky cases. It still works reasonably well when the board contains many near-complete groups. The elimination step often uses a stack-like scan similar to solutions for parentheses reduction or candy crush style problems, connecting it conceptually to stack based reductions.

Recommended for interviews: Backtracking with DFS and memoization is the expected solution. Interviewers want to see how you model the game state, prune invalid insertions, and cache repeated states. The greedy approach shows intuition but does not guarantee optimal results. Demonstrating the recursive search combined with memoization signals strong understanding of state-space exploration and optimization techniques.

Approach 1: Backtracking with DFS

This approach utilizes a Depth First Search (DFS) with backtracking strategy. The idea is to try inserting each ball in the hand between each position of the board recursively and track the number of moves to clear the board. Whenever a group of 3 or more balls is formed, it's immediately removed.

Steps:

  1. Define a recursive DFS function that tries every possible insertion for each ball in the hand.
  2. At each insertion attempt, check if a consecutive group of 3 or more balls is formed and remove them.
  3. Keep track of the minimum number of insertions needed to remove all balls. If a position has been visited with fewer balls in hand, do not proceed with that path.
  4. If the board is empty, record the minimum steps and backtrack.
  5. If it becomes impossible to clear the board, return -1.
import sys

class ZumaGame:
    def find_min_moves(self, board, hand):
        hand_counts = {char: hand.count(char) for char in hand}
        return self.dfs(board + '#', hand_counts)

    def dfs(self, board, hand_counts):
        board = self.remove_consecutives(board)
        if board == '#':
            return 0
        min_steps = sys.maxsize
        n = len(board)
        i = 0

        for j in range(n):
            if board[j] != board[i]:
                need = 3 - (j - i)
                if hand_counts.get(board[i], 0) >= need:
                    hand_counts[board[i]] -= need
                    min_steps = min(min_steps, need + self.dfs(board[:i] + board[j:], hand_counts))
                    hand_counts[board[i]] += need
                i = j

        return min_steps if min_steps != sys.maxsize else -1

    def remove_consecutives(self, board):
        n = len(board)
        stack = []
        for i in range(n):
            if stack and stack[-1][0] == board[i]:
                stack[-1] = (stack[-1][0], stack[-1][1] + 1)
            else:
                stack.append((board[i], 1))

            if stack[-1][1] >= 3:
                stack.pop()

        return ''.join(c * k for c, k in stack)

board = "WRRBBW"
hand = "RB"
game = ZumaGame()
print(game.find_min_moves(board, hand))
#include <iostream>
#include <unordered_map>
#include <string>
#include <climits>

class ZumaGame {
public:
    int findMinMoves(std::string board, std::string hand) {
        std::unordered_map<char, int> handCounts;
        for (char ch : hand) ++handCounts[ch];
        return dfs(board + "#", handCounts);
    }

private:
    std::string removeConsecutives(const std::string& board) {
        int n = board.size();
        std::string result;
        for (int i = 0; i < n; ++i) {
            if (!result.empty() && result.back() == board[i]) {
                if ((++result.back() >= 3)) {
                    result.pop_back();
                }
            } else {
                result.push_back(1);
                result.push_back(board[i]);
            }
        }
        return result;
    }

    int dfs(const std::string& board, std::unordered_map<char, int>& handCounts) {
        std::string reducedBoard = removeConsecutives(board);
        if (reducedBoard == "#") return 0;
        int minSteps = INT_MAX;

        for (int i = 0, j = 0; j <= reducedBoard.size(); ++j) {
            if (j < reducedBoard.size() && reducedBoard[i] == reducedBoard[j]) 
                continue;
            int needed = 3 - (j - i);
            if (handCounts[reducedBoard[i]] >= needed) {
                handCounts[reducedBoard[i]] -= needed;
                int result = dfs(reducedBoard.substr(0, i) + reducedBoard.substr(j), handCounts);
                if (result != -1) minSteps = std::min(minSteps, result + needed);
                handCounts[reducedBoard[i]] += needed;
            }
            i = j;
        }

        return minSteps == INT_MAX ? -1 : minSteps;
    }
};

int main() {
    ZumaGame game;
    std::string board = "WRRBBW";
    std::string hand = "RB";
    std::cout << game.findMinMoves(board, hand) << std::endl;
    return 0;
}

The given Python solution employs DFS with backtracking to explore each possible move by inserting balls into the board. A helper function, remove_consecutives, removes any three or more consecutive balls. In each DFS recursion, it checks for all possible places to insert a ball from the hand. If a group of three or more is formed, it recursively checks the reduced board state.

Complexity

Time Complexity: Between O(37) and O(516), worst case depending on hand and board length.

Space Complexity: O(n + h), where n is the board length and h is the hand length for recursion depth.

Try this approach in the editor

Approach 2: Greedy with Iteration for Partial Progress

Though the problem typically requires a full DFS due to its complexity, a greedy solution can sometimes deliver partial solutions or be used to generate helpful heuristics. This method focuses on making moves that immediately reduce the current board length or solve the most straightforward remaining groups. While not fully solving the problem, this can reduce the state space for a subsequent DFS.

import java.util.HashMap;

class ZumaGame {
    public int findMinStep(String board, String hand) {
        HashMap<Character, Integer> handCounts = new HashMap<>();
        for (char ch : hand.toCharArray()) handCounts.put(ch, handCounts.getOrDefault(ch, 0) + 1);
        return dfs(board + "#", handCounts);
    }

    private int dfs(String board, HashMap<Character, Integer> handCounts) {
        board = shrink(board);
        if ("#".equals(board)) return 0;
        int minSteps = Integer.MAX_VALUE;
        for (int i = 0, j = 0; j <= board.length(); j++) {
            if (j < board.length() && board.charAt(i) == board.charAt(j)) continue;
            int need = 3 - (j - i);
            if (handCounts.getOrDefault(board.charAt(i), 0) >= need) {
                handCounts.put(board.charAt(i), handCounts.get(board.charAt(i)) - need);
                minSteps = Math.min(minSteps, dfs(board.substring(0, i) + board.substring(j), handCounts) + need);
                handCounts.put(board.charAt(i), handCounts.get(board.charAt(i)) + need);
            }
            i = j;
        }
        return minSteps == Integer.MAX_VALUE ? -1 : minSteps;
    }

    private String shrink(String board) {
        int n = board.length();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            sb.append(board.charAt(i));
            int len = sb.length();
            if (len >= 3 && sb.charAt(len - 1) == sb.charAt(len - 2) && sb.charAt(len - 2) == sb.charAt(len - 3)) 
                sb.delete(len - 3, len);
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        ZumaGame game = new ZumaGame();
        String board = "WRRBBW";
        String hand = "RB";
        System.out.println(game.findMinStep(board, hand));
    }
}
function findMinStep(board, hand) {
    const memo = {};
    const handMap = {};
    for (let char of hand) {
        handMap[char] = (handMap[char] || 0) + 1;
    }

    function dfs(board) {
        if (board === '#') return 0;
        const key = board + '#' + Object.entries(handMap).map(([k, v]) => k + v).join('');
        if (memo[key] !== undefined) return memo[key];

        let i = 0, min_steps = Infinity;
        for (let j = 0; j <= board.length; j++) {
            if (j < board.length && board[j] !== board[i]) continue;
            let need = 3 - (j - i);
            if (handMap[board[i]] >= need) {
                handMap[board[i]] -= need;
                const tempBoard = board.slice(0, i) + board.slice(j);
                const shrinked = shrink(tempBoard);
                min_steps = Math.min(min_steps, dfs(shrinked) + need);
                handMap[board[i]] += need;
            }
            i = j;
        }

        memo[key] = min_steps === Infinity ? -1 : min_steps;
        return memo[key];
    }

    function shrink(b) {
        let result;
        do {
            result = b;
            b = b.replace(/(\w)\1{2,}/g, '');
        } while (b !== result);
        return b;
    }

    return dfs(board + '#');
}

console.log(findMinStep('WRRBBW', 'RB'));

In this Java implementation, the DFS recursively explores every possible insertion option. The shrink method collapses board parts where chains appear as a result of these insertions. Use of Java's standard classes makes the recursion and memoization straightforward.

Complexity

Time Complexity: Between O(37) and O(516), worst-case scenario due to hand and board lengths that create possibilities.

Space Complexity: O(n + h), counting for recursion depth and memoization data.

Try this approach in the editor

Complexity comparison

ApproachComplexity
Backtracking with DFS

Time Complexity: Between O(37) and O(516), worst case depending on hand and board length.

Space Complexity: O(n + h), where n is the board length and h is the hand length for recursion depth.

Greedy with Iteration for Partial Progress

Time Complexity: Between O(37) and O(516), worst-case scenario due to hand and board lengths that create possibilities.

Space Complexity: O(n + h), counting for recursion depth and memoization data.

Complexity analysis

ApproachTimeSpaceWhen to Use
Backtracking DFS with MemoizationO(b^h * n)O(b^h)General case when you must guarantee the minimum number of insertions
Greedy Iteration with Collapse SimulationO(n^2 * k)O(n)Useful for quick partial solutions or when the board has many near-complete groups

Frequently asked questions

Is Zuma Game easy or hard?

Zuma Game is classified as a Hard problem on LeetCode. The challenge comes from modeling the board state, handling chain reactions after removals, and pruning the exponential search space using memoization.

Zuma Game Python/Java solution

Python and C++ solutions often implement DFS backtracking with memoization using dictionaries or unordered maps. Java and JavaScript implementations sometimes demonstrate greedy insertion simulations, though DFS with caching is still the optimal strategy.

How to solve Zuma Game in O(n)?

An O(n) solution does not exist for the full problem because you must explore many insertion sequences to guarantee the minimum moves. The closest practical method is DFS with memoization, which prunes repeated states but still has exponential worst‑case behavior.

What is the best approach for Zuma Game?

The most reliable approach uses DFS backtracking with memoization. Each recursion tries inserting balls at different positions, then collapses groups of three or more. Memoization caches previously seen board and hand states to avoid recomputation, reducing the exponential search significantly.

Is Zuma Game asked at Google/Amazon/Meta?

Zuma Game represents the type of hard backtracking and state search problem occasionally asked in top tech interviews. Variants involving board reduction, recursive search, and memoization have appeared in interviews at companies like Google and Meta.

What data structure is used in Zuma Game?

The solution typically uses strings to represent the board, hash maps for memoization, and sometimes stack-style scans to remove consecutive groups. DFS recursion manages the state exploration while memo tables cache previously computed results.

What is the time complexity of Zuma Game?

The DFS search explores many insertion combinations, leading to exponential complexity in the worst case, often approximated as O(b^h * n) where b is branching factor and h is hand size. Memoization and pruning reduce repeated states, making it feasible for the constraints used in the problem.

Comments

Now write it yourselfClose this page and solve Zuma Game in the editor, without looking.
Practise Zuma Game