This is a simulation problem: implement the elimination mechanic from Candy Crush. We repeat two operations until the board stabilizes: find all groups of three or more identical candies in a row (horizontally or vertically), then crush them all at once and let gravity pull the remaining candies downward.
Crushing must happen simultaneously. You can't crush one group, drop, then look for the next group in the same iteration. All crushable candies in a given round must be identified before any of them are removed. After removal and gravity, you scan again, and the process repeats until a full scan finds nothing to crush.
The problem breaks down into three sub-problems that we loop over: mark (find all crushable candies), crush (set them to zero), and drop (apply gravity column by column). Once a full mark phase finds zero candidates, the board is stable.
3 <= m, n <= 50 → The board is small, at most 2,500 cells. Even O(m^2 * n^2) per iteration would be fast enough. Efficiency isn't a concern here, clarity and correctness are.1 <= board[i][j] <= 2000 → Candy values are always positive. This means we can use negative values as markers without conflicting with actual candy types.Use a separate boolean matrix to track which cells need to be crushed. Scan every cell to see if it's part of a horizontal or vertical run of three or more identical candies. Mark all such cells in the boolean matrix, crush them (set to 0), apply gravity, and repeat. This directly models the game loop: find matches, remove them, drop, check again.
A separate matrix keeps marking and reading cleanly apart: the scan only ever reads candy values from board, and only ever writes marks to crush, so no marking decision can corrupt a later comparison in the same pass.
crush of the same size as the board, initialized to all false.true in crush. Do the same for every column. Overlapping windows extend the marks, so a run of four or more is fully covered.true, set board[i][j] = 0.Loading animation...
This approach allocates a fresh boolean matrix every iteration. Candy values are always positive, so the next approach drops the extra matrix and encodes the mark in the sign of each cell instead.
All candy values are positive integers, so negating a value marks it for crushing while abs() still recovers the candy type. The board itself carries the marks, and the separate boolean matrix disappears.
The loop keeps the same shape (mark, crush, drop), with two changes. The marking phase compares absolute values and flips matched cells to negative. The crush and drop phases then merge into a single pass per column that keeps only the positive values and zero-fills the rest, so marked cells never need to be reset to zero explicitly; gravity treats anything non-positive as empty.
Negation preserves the candy type: abs(board[i][j]) recovers the original value, so already-marked cells still participate in later window checks. In a row like [3, 3, 3, 3], checking positions 0-2 negates all three. The next window at positions 1-3 compares abs(-3) == abs(3), detects the match, and negates position 3 as well. Runs longer than three are always fully marked.
abs(board[i][j]) == abs(board[i][j+1]) == abs(board[i][j+2]) and the value is non-zero, set all three cells to the negated value. Re-negating an already-marked cell writes the same value, so overlapping windows are harmless.board[i][j], board[i+1][j], board[i+2][j].Loading animation...