Bricks Falling When Hit - Complete Solution Guide
Bricks Falling When Hit is LeetCode problem 803, a Hard level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.
Problem Statement
You are given an m x n binary grid , where each 1 represents a brick and 0 represents an empty space. A brick is stable if: It is directly connected to the top of the grid, or At least one other brick in its four adjacent cells is stable . You are also given an array hits , which is a sequence of erasures we want to apply. Each time we want to erase the brick at the location hits[i] = (row i , col i ) . The brick on that location (if it exists) will disappear. Some other bricks may no longer be
Detailed Explanation
The problem describes a scenario where we have a grid of bricks, represented by 1s and empty spaces by 0s. Some bricks are 'stable' if they are connected to the top row or connected to another stable brick. We are given a list of 'hits' which represent locations where bricks are erased. The goal is to return an array where each element represents the number of bricks that fall as a result of each hit. It's important to note that a brick can fall only if it's no longer connected to the top or adjacent to another stable brick, and a 'hit' on an empty space causes no bricks to fall.
Solution Approach
The solution uses the Union Find data structure to efficiently track connected components of stable bricks. The crucial part is processing the 'hits' in reverse order. This transforms the problem of removing bricks and figuring out which ones fall, to adding bricks back and figuring out how many become stable because of it. The Union Find operations help determine how many bricks get connected to the 'top' connected component, and from this, we can determine how many bricks would have fallen if that brick had been hit.
Step-by-Step Algorithm
- Step 1: Create a copy of the original grid. Apply all the hits to this copy (set the hit positions to 0). This gives us the 'grid after hits'.
- Step 2: Initialize the Union Find data structure. Each brick in the 'grid after hits' is initially its own component. The 'parent' array represents this, and the 'size' array tracks the size of each component.
- Step 3: Create a 'dummy' top node. All bricks in the first row of the 'grid after hits' are connected to this top node using the Union Find 'union' operation.
- Step 4: Iterate through the rest of the 'grid after hits'. For each brick, check its neighbors (up, down, left, right). If a neighbor is also a brick, connect them using the Union Find 'union' operation.
- Step 5: Process the 'hits' in *reverse* order. For each hit (r, c):
- Step 6: If the original grid had a brick at (r, c):
- Step 7: Record the size of the connected component containing the top node *before* adding the brick back.
- Step 8: Add the brick back to the 'grid after hits' (set grid_after_hits[r][c] = 1).
- Step 9: Connect the brick to the top node if it's in the first row.
- Step 10: Connect the brick to its neighbors (up, down, left, right) that are also bricks using Union Find.
- Step 11: Record the size of the connected component containing the top node *after* adding the brick back.
- Step 12: The number of bricks that 'fall' as a result of this hit is the *difference* between the 'after' size and the 'before' size, minus 1 (to exclude the hit brick itself). If the difference is negative, then return 0.
- Step 13: If the original grid *didn't* have a brick at (r, c), then 0 bricks fall.
- Step 14: Store the fallen brick count in the 'result' array.
- Step 15: Reverse the 'result' array to get the correct order corresponding to the original order of hits.
Key Insights
- Insight 1: The key is to process the hits in reverse order. Instead of removing bricks, we add them back. This transforms the problem into finding how many bricks become stable with each addition.
- Insight 2: Union Find is an appropriate data structure for tracking connected components (stable bricks). We can use it to efficiently determine which bricks are connected to the top row after adding a brick back.
- Insight 3: A 'dummy' top node helps simplify the union-find process. By connecting all bricks in the top row to this node, we can easily check if a brick is connected to the top.
- Insight 4: Avoid double counting the hit brick itself. The fallen count should be the *increase* in the size of the top connected component *excluding* the hit brick that was just added.
Complexity Analysis
Time Complexity: O(m*n*alpha(m*n) + k)
Space Complexity: O(m*n)
Topics
This problem involves: Array, Union Find, Matrix.
Companies
Asked at: Snap, Tower Research Capital.