Welcome! Learn how to explore grids using Depth-First Search (DFS) - perfect for mazes, maps, and games!
Depth-First Search (DFS) = Explore as far as possible in one direction before trying another direction.
Real-World Examples:
Key Idea: Go DEEP first in one direction, then try other directions.
A grid is a 2D list - a list of lists!
# Simple 3x3 grid grid = [ [1, 0, 1], [1, 1, 0], [0, 1, 1] ] # Visual representation: # 1 0 1 # 1 1 0 # 0 1 1
Accessing cells:
grid[0][0] # Top-left: 1 grid[0][1] # Top-middle: 0 grid[1][1] # Center: 1 grid[2][2] # Bottom-right: 1 # grid[row][col]
Grid dimensions:
rows = len(grid) # Number of rows: 3 cols = len(grid[0]) # Number of columns: 3
From any cell, you can move in 4 directions:
UP (-1, 0)
↑
LEFT [ ] RIGHT
(-) ← [X] → (+)
↓
DOWN (+1, 0)
In code:
# Four directions: up, down, left, right # (row_change, col_change) directions = [ (-1, 0), # Up: row - 1 (1, 0), # Down: row + 1 (0, -1), # Left: col - 1 (0, 1) # Right: col + 1 ] # To move from current position: current_row = 1 current_col = 1 for dr, dc in directions: new_row = current_row + dr new_col = current_col + dc print(f"Neighbor at ({new_row}, {new_col})")
Before visiting a cell, check if it's valid!
def is_valid(grid, row, col): rows = len(grid) cols = len(grid[0]) # Check boundaries if row < 0 or row >= rows: return False if col < 0 or col >= cols: return False return True # Example: grid = [[1, 2], [3, 4]] print(is_valid(grid, 0, 0)) # True print(is_valid(grid, -1, 0)) # False (out of bounds) print(is_valid(grid, 2, 0)) # False (out of bounds)
DFS uses recursion to explore deeply!
The Pattern:
Visual Example:
Grid: Path DFS takes:
. . . . 1 → 2 → 3 → 4
. # # . ↓ ↓
. . . . 5 → 6 → 7 → 8
↓ ↓
9 → 10→ 11→ 12
Goes deep in one direction before trying others!
def dfs(grid, row, col, visited): # Base case 1: Out of bounds? if row < 0 or row >= len(grid): return if col < 0 or col >= len(grid[0]): return # Base case 2: Already visited? if (row, col) in visited: return # Base case 3: Is this cell blocked? (example: 0 = blocked) if grid[row][col] == 0: return # Mark as visited visited.add((row, col)) print(f"Visiting ({row}, {col})") # Recursive case: Explore all 4 directions dfs(grid, row - 1, col, visited) # Up dfs(grid, row + 1, col, visited) # Down dfs(grid, row, col - 1, visited) # Left dfs(grid, row, col + 1, visited) # Right
🎯 Functions 📋 Lists 🔄 Recursion
Your Task:
Write a function dfs_print(grid, row, col) that:
Example:
grid = [ [1, 1, 0], [1, 0, 0], [0, 0, 1] ] dfs_print(grid, 0, 0) # Output: # (0, 0) # (0, 1) # (1, 0) # These three 1s are connected! dfs_print(grid, 2, 2) # Output: # (2, 2) # This 1 is alone
Hint: Use the template above, but only explore cells with value 1!
🎯 Functions ➕ Operators 🔄 Recursion
Your Task:
Write a function count_region(grid, row, col) that:
Examples:
grid1 = [ [1, 1, 0], [1, 0, 0], [0, 0, 1] ] print(count_region(grid1, 0, 0)) # Output: 3 print(count_region(grid1, 2, 2)) # Output: 1 grid2 = [ [1, 1, 1], [0, 1, 0], [1, 1, 1] ] print(count_region(grid2, 0, 0)) # Output: 7 (all 1s connected!)
Hint: Instead of printing, add 1 and return the sum!
🎯 Functions 🔀 Conditionals 🔄 Recursion
Your Task:
Write a function can_reach(grid, start_row, start_col, target_row, target_col) that:
True if you can reach target from startFalse if blocked by 0sExamples:
grid = [ [1, 0, 1], [1, 1, 1], [0, 0, 1] ] print(can_reach(grid, 0, 0, 2, 2)) # True # Path: (0,0)→(1,0)→(1,1)→(1,2)→(2,2) print(can_reach(grid, 0, 0, 0, 2)) # False # Blocked by 0 at (0,1)
Hint: Base case - if you reach target, return True!
🎯 Functions 🔄 Recursion 📋 Lists
Your Task:
Write a function flood_fill(grid, row, col, new_value) that:
Examples:
grid = [ [1, 1, 0], [1, 0, 0], [0, 0, 1] ] result = flood_fill(grid, 0, 0, 2) # Output: # [2, 2, 0] # [2, 0, 0] # [0, 0, 1] # Connected 1s became 2s! grid2 = [ [1, 1, 1], [1, 0, 1], [1, 1, 1] ] result2 = flood_fill(grid2, 0, 0, 5) # Output: # [5, 5, 5] # [5, 0, 5] # [5, 5, 5] # All 1s connected around the 0
Hint:
🎯 Functions 🔁 Loops 🔄 Recursion
Your Task:
Write a function count_islands(grid) that:
Examples:
grid1 = [ [1, 1, 0, 0], [1, 0, 0, 1], [0, 0, 1, 1] ] print(count_islands(grid1)) # Output: 3 # Three separate island groups! grid2 = [ [1, 1, 1], [0, 1, 0], [1, 1, 1] ] print(count_islands(grid2)) # Output: 1 # All 1s are connected! grid3 = [ [0, 0, 0], [0, 0, 0], [0, 0, 0] ] print(count_islands(grid3)) # Output: 0 # No islands, all water
Hint:
🎯 Functions ➕ Operators 🔄 Recursion
Your Task:
Write a function largest_island(grid) that:
Examples:
grid = [ [1, 0, 1, 1], [1, 0, 1, 0], [0, 0, 1, 0] ] print(largest_island(grid)) # Output: 4 # Right island has 4 connected 1s grid2 = [ [1, 1], [1, 1] ] print(largest_island(grid2)) # Output: 4 # One big island!
Hint: Similar to count_islands, but track the size of each island and keep the maximum!
🎯 Functions ➕ Operators 🔄 Recursion
Your Task:
Write a function island_perimeter(grid) that:
Examples:
grid1 = [ [1] ] print(island_perimeter(grid1)) # Output: 4 # One cell = 4 edges grid2 = [ [1, 1] ] print(island_perimeter(grid2)) # Output: 6 # Two cells share one edge: 4+4-2 = 6 grid3 = [ [1, 1], [1, 1] ] print(island_perimeter(grid3)) # Output: 8 # Square has 8 outside edges
Hint: For each land cell, count how many of its 4 sides touch water or the edge!
🎯 Functions 🔄 Recursion 🔀 Conditionals
Your Task:
Write a function capture_regions(grid) that:
Examples:
grid = [ [1, 1, 1, 1], [1, 0, 0, 1], [1, 1, 1, 1] ] result = capture_regions(grid) # Output: # [1, 1, 1, 1] # [1, 1, 1, 1] # [1, 1, 1, 1] # Middle 0s are surrounded, so they become 1s grid2 = [ [1, 1, 1, 1], [1, 0, 0, 0], [1, 1, 1, 1] ] result2 = capture_regions(grid2) # Output: Same as input! # The 0s touch the edge, so they're not surrounded
Hint:
Let's apply DFS to maze-solving!
Maze Format:
🎯 Functions 🔄 Recursion 🔀 Conditionals
Your Task:
Write a function can_escape(maze) that:
True if you can reach bottom-right from top-leftFalse if blockedExamples:
maze1 = [ [1, 0, 1], [1, 1, 1], [0, 0, 1] ] print(can_escape(maze1)) # True maze2 = [ [1, 0, 1], [0, 0, 1], [0, 0, 1] ] print(can_escape(maze2)) # False
🎯 Functions 📋 Lists 🔄 Recursion
Your Task:
Write a function find_path(maze) that:
Example:
maze = [ [1, 1, 0], [0, 1, 0], [0, 1, 1] ] print(find_path(maze)) # Output: [(0,0), (0,1), (1,1), (2,1), (2,2)]
Hint: Pass current path as parameter, add to it as you recurse!
Always Check:
# 1. Boundaries if row < 0 or row >= len(grid) or col < 0 or col >= len(grid[0]): return # 2. Visited if (row, col) in visited: return # 3. Valid cell (depends on problem) if grid[row][col] == 0: # Example: 0 is blocked return
The Four Directions Pattern:
directions = [(-1,0), (1,0), (0,-1), (0,1)] for dr, dc in directions: new_row = row + dr new_col = col + dc dfs(grid, new_row, new_col, visited)
Common Mistakes:
Debug Checklist:
After mastering DFS on grids:
Keep practicing! DFS is fundamental to competitive programming! 🚀
Test your understanding:
Answers:
grid[2][3]