Number of Survival Camps - codepath/compsci_guides GitHub Wiki
Unit 11 Session 2 Advanced (Click for link to problem statements)
Problem Highlights
- 💡 Difficulty: Medium
- ⏰ Time to complete: 30 mins
- 🛠️ Topics: Union Find, Connected Components
1: U-nderstand
Understand what the interviewer is asking for by using test cases and questions about the problem.
- Established a set (2-3) of test cases to verify their own solution later.
- Established a set (1-2) of edge cases to verify their solution handles complexities.
- Have fully understood the problem and have no clarifying questions.
- Have you verified any Time/Space Constraints for this problem?
- What is a survival camp in this context?
- A camp is a group of connected
1
s that are adjacent either vertically or horizontally.
- A camp is a group of connected
- How are the camps counted?
- Camps are isolated groups of
1
s, and the goal is to return the number of such groups (connected components).
- Camps are isolated groups of
HAPPY CASE
Input: city = [
[1,1,1,1,0],
[1,1,0,1,0],
[1,1,0,0,0],
[0,0,0,0,0]
]
Output: 1
Explanation: There is only one survival camp because all the `1`s are connected.
EDGE CASE
Input: city = [
[1,1,0,0,0],
[1,1,0,0,0],
[0,0,1,0,0],
[0,0,0,1,1]
]
Output: 3
Explanation: There are three survival camps, formed by groups of `1`s that are disconnected from each other.
2: M-atch
Match what this problem looks like to known categories of problems, e.g. Linked List or Dynamic Programming, and strategies or patterns in those categories.
For Connected Components problems, we want to consider the following approaches:
- Union-Find (Disjoint Set Union): We can use Union-Find to group connected components of
1
s and count how many disjoint sets (survival camps) there are. - Grid Traversal: Instead of a DFS/BFS traversal of the grid, we will use Union-Find to efficiently manage merging adjacent cells that are part of the same camp.
3: P-lan
Plan the solution with appropriate visualizations and pseudocode.
General Idea: Use a Union-Find (Disjoint Set Union) structure to group connected 1
s into distinct components. Initially treat each 1
as a separate camp, then union adjacent 1
s into larger connected camps.
1) Initialize the Union-Find structure with `m * n` elements, where `m` is the number of rows and `n` is the number of columns.
2) Traverse the grid and treat each `1` as a potential camp. For each cell with a `1`, union it with its adjacent `1`s (either down or right).
3) Use Union-Find’s `find` and `union` operations to group connected components.
4) Return the total number of distinct camps.
⚠️ Common Mistakes
- Forgetting to initialize each
1
as its own component (camp). - Not correctly mapping the 2D grid coordinates to the 1D array used by Union-Find.
4: I-mplement
Implement the code to solve the algorithm.
class UnionFind:
def __init__(self, size):
self.parent = list(range(size)) # Initially, each element is its own parent
self.rank = [1] * size # The rank is initially 1 for all elements
self.count = 0 # The number of distinct sets (camps)
def find(self, p):
if self.parent[p] != p:
self.parent[p] = self.find(self.parent[p]) # Path compression
return self.parent[p]
def union(self, p, q):
rootP = self.find(p)
rootQ = self.find(q)
if rootP != rootQ:
# Union by rank
if self.rank[rootP] > self.rank[rootQ]:
self.parent[rootQ] = rootP
elif self.rank[rootP] < self.rank[rootQ]:
self.parent[rootP] = rootQ
else:
self.parent[rootQ] = rootP
self.rank[rootP] += 1
self.count -= 1 # Decrease the count when two camps are merged
def add_camp(self):
self.count += 1 # Add a new distinct camp
# Main function to count the number of survival camps
def num_camps(city):
if not city:
return 0
m, n = len(city), len(city[0])
# Initialize UnionFind structure
uf = UnionFind(m * n)
# Iterate through the grid
for row in range(m):
for col in range(n):
if city[row][col] == 1:
# Map the 2D grid to a 1D array index
index = row * n + col
uf.add_camp() # Each 1 is initially treated as a separate camp
# Check the neighboring cells (up, down, left, right) and union them if they are also camps (1s)
for dr, dc in [(1, 0), (0, 1)]: # Only check down and right to avoid revisiting cells
new_row, new_col = row + dr, col + dc
if 0 <= new_row < m and 0 <= new_col < n and city[new_row][new_col] == 1:
new_index = new_row * n + new_col
uf.union(index, new_index) # Union the current camp with the neighbor camp
return uf.count
5: R-eview
Review the code by running specific example(s) and recording values (watchlist) of your code's variables along the way.
Example 1:
- Input: city = [ [1,1,1,1,0], [1,1,0,1,0], [1,1,0,0,0], [0,0,0,0,0] ]
- Expected Output: 1
- Watchlist:
- Ensure that the Union-Find structure correctly groups all adjacent
1
s into one component. - Verify that the
count
reflects the total number of distinct camps.
- Ensure that the Union-Find structure correctly groups all adjacent
6: E-valuate
Evaluate the performance of your algorithm and state any strong/weak or future potential work.
Assume m
is the number of rows and n
is the number of columns in the grid.
- Time Complexity:
O(m * n * α(m * n))
, whereα
is the inverse Ackermann function (very slow-growing) because of the Union-Find operations with path compression. - Space Complexity:
O(m * n)
due to the Union-Find data structure.