Skip to content

Commit 2e114b3

Browse files
committed
Updated readme
1 parent 3358194 commit 2e114b3

File tree

6 files changed

+957
-637
lines changed

6 files changed

+957
-637
lines changed

README.md

Lines changed: 719 additions & 530 deletions
Large diffs are not rendered by default.

src/main/python/g0101_0200/s0198_house_robber/readme.md

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,24 +36,38 @@ Given an integer array `nums` representing the amount of money of each house, re
3636
* `1 <= nums.length <= 100`
3737
* `0 <= nums[i] <= 400`
3838

39-
## Solution
39+
To solve the House Robber problem, we can utilize dynamic programming to find the maximum amount of money we can rob without alerting the police. Here's how we can approach this problem:
40+
41+
1. **Initialize Variables**:
42+
- Initialize two variables, `prev_max` and `curr_max`, to keep track of the maximum amount of money robbed from previous houses and the current house, respectively.
43+
44+
2. **Iterate Through Houses**:
45+
- Iterate through the array of house values `nums`.
46+
47+
3. **Calculate Maximum Amount of Money Robbed**:
48+
- For each house, update `curr_max` to the maximum value between the sum of the value of the current house and `prev_max`, and `prev_max`.
49+
50+
4. **Return Result**:
51+
- After iterating through all houses, return `curr_max`, which represents the maximum amount of money that can be robbed without alerting the police.
52+
53+
Let's implement this approach:
4054

4155
```python
4256
class Solution:
4357
def rob(self, nums: List[int]) -> int:
44-
if len(nums) == 0:
58+
if not nums:
4559
return 0
4660
if len(nums) == 1:
4761
return nums[0]
48-
if len(nums) == 2:
49-
return max(nums[0], nums[1])
5062

51-
profit = [0] * len(nums)
52-
profit[0] = nums[0]
53-
profit[1] = max(nums[1], nums[0])
63+
prev_max = curr_max = 0
5464

55-
for i in range(2, len(nums)):
56-
profit[i] = max(profit[i - 1], nums[i] + profit[i - 2])
65+
for num in nums:
66+
temp = curr_max
67+
curr_max = max(prev_max + num, curr_max)
68+
prev_max = temp
5769

58-
return profit[len(nums) - 1]
59-
```
70+
return curr_max
71+
```
72+
73+
This solution ensures that we calculate the maximum amount of money that can be robbed without alerting the police in linear time complexity O(n) and constant space complexity O(1), meeting the problem constraints.

src/main/python/g0101_0200/s0200_number_of_islands/readme.md

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,26 +42,51 @@ An **island** is surrounded by water and is formed by connecting adjacent lands
4242
* `1 <= m, n <= 300`
4343
* `grid[i][j]` is `'0'` or `'1'`.
4444

45-
## Solution
45+
To solve the Number of Islands problem, we can utilize Depth-First Search (DFS) to traverse the grid and identify the islands. Here's a step-by-step approach to solve this problem:
46+
47+
1. **Define DFS Function**:
48+
- Define a DFS function to traverse the grid recursively.
49+
- This function will mark visited cells as `'0'` to avoid revisiting them.
50+
- It will explore adjacent cells (up, down, left, right) and continue DFS traversal if the adjacent cell is land (`'1'`).
51+
52+
2. **Iterate Through Grid**:
53+
- Iterate through each cell in the grid.
54+
55+
3. **Count Islands**:
56+
- For each cell with land (`'1'`), call the DFS function to explore the island.
57+
- Increment the count of islands by 1 after each DFS traversal.
58+
59+
4. **Return Count**:
60+
- After traversing the entire grid, return the count of islands.
61+
62+
Let's implement this approach:
4663

4764
```python
4865
class Solution:
4966
def numIslands(self, grid: List[List[str]]) -> int:
50-
def dfs(grid, x, y):
51-
if x < 0 or x >= len(grid) or y < 0 or y >= len(grid[0]) or grid[x][y] != '1':
67+
def dfs(grid, i, j):
68+
if i < 0 or i >= len(grid) or j < 0 or j >= len(grid[0]) or grid[i][j] == '0':
5269
return
53-
grid[x][y] = 'x'
54-
dfs(grid, x + 1, y)
55-
dfs(grid, x - 1, y)
56-
dfs(grid, x, y + 1)
57-
dfs(grid, x, y - 1)
70+
grid[i][j] = '0' # Mark the current cell as visited
71+
# Explore adjacent cells
72+
dfs(grid, i+1, j)
73+
dfs(grid, i-1, j)
74+
dfs(grid, i, j+1)
75+
dfs(grid, i, j-1)
5876

59-
islands = 0
60-
if grid and grid[0]:
61-
for i in range(len(grid)):
62-
for j in range(len(grid[0])):
63-
if grid[i][j] == '1':
64-
dfs(grid, i, j)
65-
islands += 1
66-
return islands
67-
```
77+
if not grid:
78+
return 0
79+
80+
num_islands = 0
81+
rows, cols = len(grid), len(grid[0])
82+
83+
for i in range(rows):
84+
for j in range(cols):
85+
if grid[i][j] == '1':
86+
num_islands += 1
87+
dfs(grid, i, j)
88+
89+
return num_islands
90+
```
91+
92+
This solution efficiently counts the number of islands in the given grid by performing DFS traversal on each unvisited land cell. It has a time complexity of O(M * N), where M is the number of rows and N is the number of columns in the grid.

src/main/python/g0201_0300/s0206_reverse_linked_list/readme.md

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,46 @@ Given the `head` of a singly linked list, reverse the list, and return _the reve
3636

3737
**Follow up:** A linked list can be reversed either iteratively or recursively. Could you implement both?
3838

39-
## Solution
39+
To solve the Reverse Linked List problem, we can either use an iterative approach or a recursive approach. Here are the steps for both approaches:
40+
41+
### Iterative Approach:
42+
1. **Initialize Pointers**: Initialize three pointers, `prev`, `curr`, and `next`.
43+
2. **Iterate Through List**: Iterate through the list until `curr` is not `None`.
44+
- Update `next` to `curr.next`.
45+
- Reverse the `curr` node's pointer to point to `prev` instead of `next`.
46+
- Move `prev` to `curr` and `curr` to `next`.
47+
3. **Return Head**: Return `prev` as the new head of the reversed list.
48+
49+
### Recursive Approach:
50+
1. **Define Recursive Function**: Define a recursive function that takes a node as input.
51+
2. **Base Case**: If the input node or its next node is `None`, return the node itself.
52+
3. **Recursive Call**: Recursively call the function on the next node.
53+
4. **Reverse Pointers**: Reverse the pointers of the current node and its next node.
54+
5. **Return Head**: Return the new head of the reversed list.
55+
56+
Let's implement both approaches:
4057

4158
```python
42-
# Definition for singly-linked list.
43-
# class ListNode:
44-
# def __init__(self, val=0, next=None):
45-
# self.val = val
46-
# self.next = next
4759
class Solution:
48-
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
49-
prev = None
50-
curr = head
51-
while curr is not None:
60+
def reverseListIterative(self, head: ListNode) -> ListNode:
61+
prev, curr = None, head
62+
while curr:
5263
next_node = curr.next
5364
curr.next = prev
5465
prev = curr
5566
curr = next_node
5667
return prev
57-
```
68+
69+
def reverseListRecursive(self, head: ListNode) -> ListNode:
70+
def reverse(node):
71+
if not node or not node.next:
72+
return node
73+
new_head = reverse(node.next)
74+
node.next.next = node
75+
node.next = None
76+
return new_head
77+
78+
return reverse(head)
79+
```
80+
81+
These solutions will efficiently reverse the linked list either iteratively or recursively, meeting the problem constraints. The time complexity for both approaches is O(n), where n is the number of nodes in the linked list.

src/main/python/g0201_0300/s0207_course_schedule/readme.md

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,35 +35,79 @@ Return `true` if you can finish all courses. Otherwise, return `false`.
3535
* <code>0 <= a<sub>i</sub>, b<sub>i</sub> < numCourses</code>
3636
* All the pairs prerequisites[i] are **unique**.
3737

38-
## Solution
38+
To solve the Course Schedule problem, we can use a graph-based approach with topological sorting. We'll represent the courses and their prerequisites as a directed graph, and then perform a topological sort to determine if there exists any cycle in the graph. If there is a cycle, it means there is a dependency loop, and it won't be possible to complete all courses.
39+
40+
### Steps:
41+
42+
1. **Build the Graph**:
43+
- Create an adjacency list to represent the directed graph.
44+
- Iterate through the `prerequisites` array and add edges to the graph.
45+
46+
2. **Perform Topological Sorting**:
47+
- Implement a function for topological sorting, which can be done using Depth-First Search (DFS) or Breadth-First Search (BFS).
48+
- In each approach, keep track of the visited nodes and the current path.
49+
- If during DFS, we encounter a node that is already in the current path, it indicates a cycle, and we return False.
50+
- If the sorting completes without finding a cycle, return True.
51+
52+
3. **Check for Cycle**:
53+
- If any node has a cycle in its path, return False.
54+
55+
4. **Return Result**:
56+
- If no cycle is found, return True, indicating it's possible to finish all courses.
57+
58+
### Implementation:
3959

4060
```python
41-
class Solution:
42-
WHITE = 0
43-
GRAY = 1
44-
BLACK = 2
61+
from collections import defaultdict
4562

63+
class Solution:
4664
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
47-
adj = [[] for _ in range(numCourses)]
48-
for pre in prerequisites:
49-
adj[pre[1]].append(pre[0])
65+
# Build the graph
66+
graph = defaultdict(list)
67+
for course, prereq in prerequisites:
68+
graph[course].append(prereq)
5069

51-
colors = [self.WHITE] * numCourses
70+
# Function for topological sorting using DFS
71+
def dfs(course, visited, path):
72+
if course in path:
73+
return False # Cycle detected
74+
if visited[course]:
75+
return True # Already visited
76+
visited[course] = True
77+
path.add(course)
78+
for neighbor in graph[course]:
79+
if not dfs(neighbor, visited, path):
80+
return False
81+
path.remove(course)
82+
return True
5283

53-
for i in range(numCourses):
54-
if colors[i] == self.WHITE and adj[i] and self.hasCycle(adj, i, colors):
84+
# Perform topological sorting for each course
85+
for course in range(numCourses):
86+
visited = [False] * numCourses
87+
path = set()
88+
if not dfs(course, visited, path):
5589
return False
90+
5691
return True
92+
```
5793

58-
def hasCycle(self, adj: List[List[int]], node: int, colors: List[int]) -> bool:
59-
colors[node] = self.GRAY
60-
61-
for nei in adj[node]:
62-
if colors[nei] == self.GRAY:
63-
return True
64-
if colors[nei] == self.WHITE and self.hasCycle(adj, nei, colors):
65-
return True
66-
67-
colors[node] = self.BLACK
68-
return False
69-
```
94+
### Explanation:
95+
96+
1. **Build the Graph**:
97+
- We use a defaultdict to create an adjacency list representation of the directed graph.
98+
- We iterate through the `prerequisites` array and add edges to the graph.
99+
100+
2. **Perform Topological Sorting**:
101+
- We implement a function `dfs` for topological sorting using Depth-First Search (DFS).
102+
- We keep track of visited nodes and the current path to detect cycles.
103+
- If we encounter a node that is already in the current path, it indicates a cycle, and we return False.
104+
- Otherwise, if DFS completes without finding a cycle, we return True.
105+
106+
3. **Check for Cycle**:
107+
- We iterate through each course and perform topological sorting.
108+
- If any node has a cycle in its path, we return False.
109+
110+
4. **Return Result**:
111+
- If no cycle is found, we return True, indicating it's possible to finish all courses.
112+
113+
This solution has a time complexity of O(V + E), where V is the number of courses and E is the number of prerequisites. The space complexity is O(V + E) for storing the graph.

0 commit comments

Comments
 (0)