-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7733f22
commit 960d70d
Showing
7 changed files
with
303 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
## Graph | ||
|
||
### Depth-first search | ||
|
||
**Recursive** | ||
```python | ||
for node in graph: | ||
dfs(node, graph) | ||
|
||
def dfs(node, graph): | ||
for neighbor in graph[node]: | ||
dfs(neighbor, graph) | ||
``` | ||
|
||
### Minimum island problem | ||
|
||
**Statement**: Given a 2D grid of Land and Water, find the smallest island in the grid. An island is defined as land connected horizontally or vertically. | ||
|
||
```python | ||
grid = [ | ||
["W", "L", "W", "W", "W"], | ||
["W", "L", "W", "W", "W"], | ||
["W", "W", "W", "L", "W"], | ||
["W", "W", "L", "L", "W"], | ||
["L", "W", "W", "L", "L"], | ||
["L", "L", "W", "W", "W"], | ||
] | ||
minimum_island(grid) # 2 | ||
``` | ||
**Approach**: | ||
1. Iterate through the grid with nested ```for``` loops. | ||
2. On any land cell, perform a **depth-first search** to find the size of the island. | ||
3. Keep track of the visited cells to avoid infinite loops. | ||
|
||
### Closest carrot problem | ||
|
||
**Statement**: Given a 2D grid of Open Spaces "O"s, Walls "X"s, and Carrots "C"s, find the closest carrot from a given initial position. | ||
|
||
```python | ||
grid = [ | ||
['O', 'O', 'O', 'O', 'O'], | ||
['O', 'X', 'O', 'O', 'O'], | ||
['O', 'X', 'X', 'O', 'O'], | ||
['O', 'X', 'C', 'O', 'O'], | ||
['O', 'X', 'X', 'O', 'O'], | ||
['C', 'O', 'O', 'O', 'O'], | ||
] | ||
|
||
closest_carrot(grid, 1, 2) # -> 4 | ||
``` | ||
**Approach**: | ||
1. Use a **breadth-first search** to find the shortest path from the initial position to the closest carrot. **BFS** will explore all directions equally, so it will find the shortest path. | ||
2. Keep track of the visited cells to avoid infinite loops. | ||
3. Keep track of the distance to the origin by adding 1 to a ```distance``` variable. | ||
4. Return the ```distance``` when the carrot is found. | ||
|
||
### Longest path problem | ||
|
||
**Statement**: Givenn an adjacency list for a **directed acyclic graph** (DAG), find the longest path (number of edges) in the graph. | ||
|
||
|
||
<table> | ||
<tr> | ||
<td> | ||
|
||
```python | ||
graph = { | ||
'a': ['c', 'b'], | ||
'b': ['c'], | ||
'c': [] | ||
} | ||
longest_path(graph) # -> 2 | ||
``` | ||
|
||
</td> | ||
<td style="text-align: center;"> | ||
|
||
|
||
```mermaid | ||
graph TD | ||
a --> c | ||
a --> b | ||
b --> c | ||
``` | ||
|
||
</td> | ||
</tr> | ||
</table> | ||
|
||
|
||
**Approach**: | ||
1. Find the terminal nodes of the graph. A terminal node is a node with no outgoing edges. | ||
- Each terminal node has the potential to be the start of the longest path. | ||
- We need to assign a distance to each node, in particular a terminal node has a distance of 0 (we are going to count backwards). | ||
2. For each node in the graph, do a **depth-first search**. | ||
3. The base case is an already visited node, in which case we return the distance. | ||
4. The recursive case is to return the maximum distance of the neighbors plus 1. | ||
5. Finally, return the maximum distance found. | ||
|
||
**Complexity**: | ||
- Time: O(E) where E is the number of edges in the graph. | ||
- Space: O(N) where N is the number of nodes in the graph. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
## Dynamic Programming | ||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
""" | ||
closest carrot | ||
Write a function, closest_carrot, that takes in a grid, a starting row, | ||
and a starting column. In the grid, 'X's are walls, 'O's are open | ||
spaces, and 'C's are carrots. The function should return a number | ||
representing the length of the shortest path from the starting position | ||
to a carrot. You may move up, down, left, or right, but | ||
cannot pass through walls (X). | ||
If there is no possible path to a carrot, then return -1. | ||
""" | ||
|
||
from collections import deque | ||
|
||
def closest_carrot(grid, starting_row, starting_col): | ||
visited = set((starting_row, starting_col)) | ||
|
||
q = deque([]) | ||
q.append((starting_row, starting_col, 0)) | ||
|
||
deltas = [(1, 0), (-1,0), (0, 1), (0, -1)] | ||
|
||
while len(q) > 0: | ||
r, c, dist = q.popleft() | ||
|
||
if grid[r][c] == "C": | ||
return dist | ||
|
||
for delta in deltas: | ||
neighbor_row = r + delta[0] | ||
neighbor_col = c + delta[1] | ||
|
||
inbound_row = 0 <= neighbor_row < len(grid) | ||
inbound_col = 0 <= neighbor_col < len(grid[0]) | ||
|
||
if inbound_row and inbound_col: | ||
pos = (neighbor_row, neighbor_col) | ||
if pos not in visited: | ||
if grid[neighbor_row][neighbor_col] != "X": | ||
q.append(( | ||
neighbor_row, | ||
neighbor_col, | ||
dist+1 | ||
)) | ||
visited.add(pos) | ||
return -1 | ||
|
||
grid = [ | ||
['O', 'O', 'X', 'O', 'O'], | ||
['O', 'X', 'O', 'X', 'O'], | ||
['O', 'X', 'X', 'O', 'O'], | ||
['O', 'X', 'C', 'O', 'O'], | ||
['O', 'X', 'X', 'O', 'O'], | ||
['C', 'O', 'O', 'O', 'O'], | ||
] | ||
|
||
print(closest_carrot(grid, 1, 2)) # -> 4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
""" | ||
longest path | ||
Write a function, longest_path, that takes in an adjacency list for a | ||
directed acyclic graph. The function should return the length of the | ||
longest path within the graph. A path may start and end at any two nodes. | ||
The length of a path is considered the number of edges in the path, | ||
not the number of nodes. | ||
""" | ||
|
||
def longest_path(graph): | ||
# sounds like a DFS problem | ||
# I need to go to any given node | ||
# and go to the end | ||
# store how many edges I passed to get to that node | ||
visited = dict() | ||
for node in graph: | ||
if graph[node] == []: | ||
visited[node] = 0 | ||
for node in graph: | ||
explore(node, graph, visited) | ||
|
||
return max(visited.values()) | ||
|
||
def explore(node, graph, visited): | ||
|
||
if node in visited: | ||
return visited[node] | ||
|
||
|
||
largest = 0 | ||
for neighbor in graph[node]: | ||
path = explore(neighbor, graph, visited) | ||
if path > largest: | ||
largest = path | ||
visited[node] = 1 +largest | ||
return visited[node] | ||
|
||
|
||
|
||
|
||
graph = { | ||
'a': ['c', 'b'], | ||
'b': ['c'], | ||
'c': [] | ||
} | ||
|
||
print(longest_path(graph)) # -> 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
def minimum_island(grid): | ||
visited = set() | ||
n_rows = len(grid) | ||
n_cols = len(grid[0]) | ||
min_size = n_rows*n_cols | ||
# need to iterate through every row and column of grid | ||
# start at the top left | ||
r, c = 0, 0 | ||
# we need a stack to do a DFS | ||
for r in range (n_rows): | ||
for c in range(n_cols): | ||
# then we need to do a DFS of the grid | ||
if (r, c) in visited: | ||
continue | ||
cell = grid[r][c] | ||
visited.add((r,c)) | ||
if cell == "L": | ||
stack = [] | ||
stack.append((r,c)) | ||
current_size = 0 | ||
while len(stack)>0: | ||
#populate the stack | ||
# add the cell above handling limits | ||
r, c = stack.pop() | ||
visited.add((r,c)) | ||
current_size+=1 | ||
if r > 0: | ||
up = (r-1, c) | ||
if (up not in visited) and "L"==grid[up[0]][up[1]]: | ||
stack.append(up) | ||
# add the cell down, handling out of bounds | ||
if r < n_rows - 1: | ||
down = (r+1, c) | ||
if (down not in visited) and "L"==grid[down[0]][down[1]]: | ||
stack.append(down) | ||
# add left | ||
if c > 0: | ||
left = (r, c-1) | ||
if (left not in visited) and ("L"==grid[left[0]][left[1]]): | ||
stack.append(left) | ||
if c < n_cols -1: | ||
right=(r, c+1) | ||
if (right not in visited) and ("L"==grid[right[0]][right[1]]): | ||
stack.append(right) | ||
if len(stack)==0: | ||
if current_size<min_size: | ||
min_size=current_size | ||
|
||
return min_size | ||
|
||
if __name__ == "__main__": | ||
grid = [ | ||
['W', 'L', 'W', 'W', 'W'], | ||
['W', 'L', 'W', 'W', 'W'], | ||
['W', 'W', 'W', 'L', 'W'], | ||
['W', 'W', 'L', 'L', 'W'], | ||
['L', 'W', 'W', 'L', 'L'], | ||
['L', 'L', 'W', 'W', 'W'], | ||
] | ||
|
||
print(minimum_island(grid)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
""" | ||
semesters required | ||
Write a function, semesters_required, that takes in a number of | ||
courses (n) and a list of prerequisites as arguments. Courses | ||
have ids ranging from 0 through n - 1. A single prerequisite of | ||
(A, B) means that course A must be taken before course B. Return | ||
the minimum number of semesters required to complete all n | ||
courses. There is no limit on how many courses you can take in | ||
a single semester, as long the prerequisites of a course are | ||
satisfied before taking it. | ||
Note that given prerequisite (A, B), you cannot take course A | ||
and course B concurrently in the same semester. You must take | ||
A in some semester before B. | ||
You can assume that it is possible to eventually complete | ||
all courses. | ||
""" | ||
|
||
def semesters_required(num_courses, prereqs): | ||
pass # todo | ||
|
||
|
||
num_courses = 6 | ||
prereqs = [ | ||
(1, 2), | ||
(2, 4), | ||
(3, 5), | ||
(0, 5), | ||
] | ||
semesters_required(num_courses, prereqs) # -> 3 |