|
5 | 5 | - Space: O(N)
|
6 | 6 | - N = Number of elements in grid
|
7 | 7 |
|
8 |
| -Using a visited set and recursion to achieve a solution. |
9 |
| -``` |
10 |
| -class Solution: |
11 |
| - def numIslands(self, grid: List[List[str]]) -> int: |
12 |
| - def traverse_helper(grid): |
13 |
| - n_islands = 0 |
14 |
| - visited = set() |
15 |
| - for y_index, y in enumerate(grid): |
16 |
| - for x_index, x in enumerate(y): |
17 |
| - if (x_index, y_index) not in visited and x == '1': |
18 |
| - n_islands += 1 |
19 |
| - traverse_islands_dfs_recursion(x_index, y_index, grid, visited) |
20 |
| - return n_islands |
21 |
| - |
22 |
| - def traverse_islands_dfs_recursion(x, y, grid, visited): |
23 |
| - if not within_bounds(x, y, grid) or (x,y) in visited or grid[y][x] == '0': |
24 |
| - return |
25 |
| - visited.add((x,y)) |
26 |
| - for neighbor_x, neighbor_y in get_neighbors_gen(x, y, grid): |
27 |
| - traverse_islands_dfs_recursion(neighbor_x, neighbor_y, grid, visited) |
28 |
| - |
29 |
| - def get_neighbors_gen(x, y, grid): |
30 |
| - yield x, y-1 # top |
31 |
| - yield x, y+1 # bottom |
32 |
| - yield x-1, y # left |
33 |
| - yield x+1, y # right |
34 |
| - |
35 |
| - def within_bounds(x, y, grid): |
36 |
| - if y >= 0 and y < len(grid) and x >= 0 and x < len(grid[0]): |
37 |
| - return True |
38 |
| - return False |
39 |
| - |
40 |
| - return traverse_helper(grid) |
41 |
| -``` |
| 8 | +By going around the grid, we can DFS on the first '1' encountered per island. |
| 9 | +The DFS will only call the recursion on neighboring elements if the element is a '1', else skip it. |
42 | 10 |
|
43 |
| -## BFS Recursive Solution |
44 |
| -- Runtime: O(N) |
45 |
| -- Space: O(N) |
46 |
| -- N = Number of elements in grid |
| 11 | +We can save some space by reusing the given the grid. |
| 12 | +You should ask the interviewer if you are allowed to modify the original grid. |
| 13 | +We can then use another number such as "2" to represented an already visited island, therefore, no longer needing a visited set during our BFS or DFS. |
47 | 14 |
|
48 | 15 | ```
|
| 16 | +class Solution(object): |
| 17 | + def numIslands(self, grid): |
49 | 18 |
|
| 19 | + def dfs(r, c): |
| 20 | + grid[r][c] = '2' |
| 21 | + for x, y in get_neighbors(r, c): |
| 22 | + if grid[x][y] == '1': |
| 23 | + dfs(x, y) |
| 24 | +
|
| 25 | + def get_neighbors(x, y): |
| 26 | + dirs = [(1,0),(0,1),(-1,0),(0,-1)] |
| 27 | + for _x, _y in dirs: |
| 28 | + _x += x |
| 29 | + _y += y |
| 30 | + if 0 <= _x < len(grid) and 0 <= _y < len(grid[0]): |
| 31 | + yield (_x, _y) |
| 32 | +
|
| 33 | + n_islands = 0 |
| 34 | + for r, row in enumerate(grid): |
| 35 | + for c, col in enumerate(row): |
| 36 | + if col == '1': |
| 37 | + n_islands += 1 |
| 38 | + dfs(r, c) |
| 39 | + return n_islands |
50 | 40 | ```
|
51 | 41 |
|
52 | 42 | ## BFS Iterative Solution
|
53 |
| -- Runtime: O(N) |
54 |
| -- Space: O(N) |
55 |
| -- N = Number of elements in grid |
| 43 | +- Runtime: O(N * M) |
| 44 | +- Space: O(N * M) |
| 45 | +- N = Number of Rows |
| 46 | +- M = Number of Columns |
| 47 | + |
| 48 | +Remember BFS uses a queue, gathering all the neighboring elements and adding them into the queue. |
56 | 49 |
|
57 |
| -Similar concept to the previous DFS recursion but now using BFS and a stack. |
58 |
| -``` |
59 |
| -class Solution: |
60 |
| - def numIslands(self, grid: List[List[str]]) -> int: |
61 |
| - def traverse_helper(grid): |
62 |
| - n_islands = 0 |
63 |
| - visited = set() |
64 |
| - for y_index, y in enumerate(grid): |
65 |
| - for x_index, x in enumerate(y): |
66 |
| - if (x_index, y_index) not in visited and x == '1': |
67 |
| - n_islands += 1 |
68 |
| - traverse_islands_bfs_iterative(x_index, y_index, grid, visited) |
69 |
| - return n_islands |
70 |
| - |
71 |
| - def traverse_islands_bfs_iterative(x, y, grid, visited): |
72 |
| - stack = list() |
73 |
| - stack.append((x,y)) |
74 |
| - while len(stack) > 0: |
75 |
| - x_index, y_index = stack.pop() |
76 |
| - visited.add((x_index, y_index)) |
77 |
| - for x_neighbor, y_neighbor in get_neighbors_gen(x_index, y_index, grid): |
78 |
| - if within_bounds(x_neighbor, y_neighbor, grid) \ |
79 |
| - and (x_neighbor, y_neighbor) not in visited \ |
80 |
| - and grid[y_neighbor][x_neighbor] == '1': |
81 |
| - stack.append((x_neighbor, y_neighbor)) |
82 |
| - |
83 |
| - def get_neighbors_gen(x, y, grid): |
84 |
| - yield x, y-1 # top |
85 |
| - yield x, y+1 # bottom |
86 |
| - yield x-1, y # left |
87 |
| - yield x+1, y # right |
88 |
| - |
89 |
| - def within_bounds(x, y, grid): |
90 |
| - if y >= 0 and y < len(grid) and x >= 0 and x < len(grid[0]): |
91 |
| - return True |
92 |
| - return False |
93 |
| - |
94 |
| - return traverse_helper(grid) |
95 | 50 | ```
|
| 51 | +from collections import deque |
96 | 52 |
|
97 |
| -## Optimized Space BFS Iterative Solution |
98 |
| -- Runtime: O(N) |
99 |
| -- Space: O(N) |
100 |
| -- N = Number of elements in grid |
| 53 | +class Solution(object): |
| 54 | + def numIslands(self, grid): |
101 | 55 |
|
102 |
| -We can achieve save some space by reusing the given the grid. You should ask the interviewer if you are allowed to modify the original grid. We can then use another number such as "-1" to represented an already visited island, therefore, no longer needing a visited set during our BFS or DFS. |
103 |
| -``` |
104 |
| -class Solution: |
105 |
| - def numIslands(self, grid: List[List[str]]) -> int: |
106 |
| - def traverse_helper(grid): |
107 |
| - n_islands = 0 |
108 |
| - for y_index, y in enumerate(grid): |
109 |
| - for x_index, x in enumerate(y): |
110 |
| - if x == '1': |
111 |
| - n_islands += 1 |
112 |
| - traverse_islands_bfs_iterative(x_index, y_index, grid) |
113 |
| - return n_islands |
114 |
| - |
115 |
| - def traverse_islands_bfs_iterative(x, y, grid): |
116 |
| - stack = list() |
117 |
| - stack.append((x,y)) |
118 |
| - while len(stack) > 0: |
119 |
| - x_index, y_index = stack.pop() |
120 |
| - grid[y_index][x_index] = '-1' |
121 |
| - for x_neighbor, y_neighbor in get_neighbors_gen(x_index, y_index, grid): |
122 |
| - if within_bounds(x_neighbor, y_neighbor, grid) \ |
123 |
| - and grid[y_neighbor][x_neighbor] == '1': |
124 |
| - stack.append((x_neighbor, y_neighbor)) |
125 |
| - |
126 |
| - def get_neighbors_gen(x, y, grid): |
127 |
| - yield x, y-1 # top |
128 |
| - yield x, y+1 # bottom |
129 |
| - yield x-1, y # left |
130 |
| - yield x+1, y # right |
131 |
| - |
132 |
| - def within_bounds(x, y, grid): |
133 |
| - if y >= 0 and y < len(grid) and x >= 0 and x < len(grid[0]): |
134 |
| - return True |
135 |
| - return False |
136 |
| - |
137 |
| - return traverse_helper(grid) |
| 56 | + def get_neighbors(x, y): |
| 57 | + dirs = [(1,0),(0,1),(-1,0),(0,-1)] |
| 58 | + for _x, _y in dirs: |
| 59 | + _x += x |
| 60 | + _y += y |
| 61 | + if 0 <= _x < len(grid) and 0 <= _y < len(grid[0]): |
| 62 | + yield (_x, _y) |
| 63 | +
|
| 64 | + n_islands = 0 |
| 65 | + for r, row in enumerate(grid): |
| 66 | + for c, col in enumerate(row): |
| 67 | + if col == '1': |
| 68 | + n_islands += 1 |
| 69 | + grid[r][c] == '2' |
| 70 | + queue = deque([(r, c)]) |
| 71 | + while queue: |
| 72 | + x, y = queue.pop() |
| 73 | + for _x, _y in get_neighbors(x, y): |
| 74 | + if grid[_x][_y] == '1': |
| 75 | + grid[_x][_y] = '2' |
| 76 | + queue.appendleft((_x, _y)) |
| 77 | + return n_islands |
138 | 78 | ```
|
0 commit comments