Skip to content

Commit 522aed5

Browse files
committed
add more solutions
1 parent 2e6563a commit 522aed5

15 files changed

+1018
-0
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# 123. [Best Time to Buy and Sell Stock III](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/)
2+
3+
## Approach 1: Dynamic Programming with State Variables
4+
5+
### Solution
6+
python
7+
```python
8+
# Time Complexity: O(n)
9+
# Space Complexity: O(1)
10+
11+
class Solution:
12+
def maxProfit(self, prices):
13+
hold1 = float('-inf')
14+
hold2 = float('-inf')
15+
release1 = 0
16+
release2 = 0
17+
18+
for price in prices:
19+
# First transaction
20+
release1 = max(release1, hold1 + price) # Sell stock held by hold1
21+
hold1 = max(hold1, -price) # Buy stock
22+
23+
# Second transaction
24+
release2 = max(release2, hold2 + price) # Sell stock held by hold2
25+
hold2 = max(hold2, release1 - price) # Buy stock after first sell
26+
27+
return release2 # Maximum profit from two transactions
28+
```
29+
30+
## Approach 2: Dynamic Programming with 2D DP Array
31+
32+
### Solution
33+
python
34+
```python
35+
# Time Complexity: O(n)
36+
# Space Complexity: O(n)
37+
38+
class Solution:
39+
def maxProfit(self, prices):
40+
if not prices or len(prices) <= 1:
41+
return 0
42+
43+
k = 2 # Maximum number of transactions
44+
n = len(prices)
45+
# dp[i][j] = maximum profit using at most i transactions by time j
46+
dp = [[0] * n for _ in range(k + 1)]
47+
48+
for i in range(1, k + 1):
49+
maxDiff = -prices[0]
50+
for j in range(1, n):
51+
# Previous maximum profit obtained with `i` transactions or profit after selling stock by day `j`
52+
dp[i][j] = max(dp[i][j - 1], prices[j] + maxDiff)
53+
# Max profit after buying stock on day `j`
54+
maxDiff = max(maxDiff, dp[i - 1][j] - prices[j])
55+
56+
return dp[k][n - 1] # Maximum profit with at most `k` transactions at the last day
57+
```
58+
59+
## Approach 3: Forward and Backward Pass
60+
61+
### Solution
62+
python
63+
```python
64+
# Time Complexity: O(n)
65+
# Space Complexity: O(n)
66+
67+
class Solution:
68+
def maxProfit(self, prices):
69+
n = len(prices)
70+
if n <= 1:
71+
return 0
72+
73+
leftProfits = [0] * n
74+
rightProfits = [0] * n
75+
76+
minPrice = prices[0]
77+
for i in range(1, n):
78+
minPrice = min(minPrice, prices[i])
79+
leftProfits[i] = max(leftProfits[i - 1], prices[i] - minPrice)
80+
81+
maxPrice = prices[n - 1]
82+
for i in range(n - 2, -1, -1):
83+
maxPrice = max(maxPrice, prices[i])
84+
rightProfits[i] = max(rightProfits[i + 1], maxPrice - prices[i])
85+
86+
maxProfit = 0
87+
for i in range(n):
88+
maxProfit = max(maxProfit, leftProfits[i] + rightProfits[i])
89+
90+
return maxProfit
91+
```
92+
93+

python/clone_graph.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# 133. [Clone Graph](https://leetcode.com/problems/clone-graph/)
2+
3+
## Approach: Depth-First Search (DFS) with HashMap
4+
5+
### Solution
6+
```python
7+
# Time Complexity: O(n), where n is the number of nodes in the graph
8+
# Space Complexity: O(n), for the HashMap and recursion stack
9+
from collections import defaultdict
10+
11+
class Node:
12+
def __init__(self, val=0, neighbors=None):
13+
self.val = val
14+
self.neighbors = neighbors if neighbors is not None else []
15+
16+
class Solution:
17+
def __init__(self):
18+
self.map = {}
19+
20+
def cloneGraph(self, node):
21+
if node is None:
22+
return None
23+
24+
# If the node is already cloned, return the cloned node
25+
if node in self.map:
26+
return self.map[node]
27+
28+
# Clone the current node
29+
clone = Node(node.val)
30+
self.map[node] = clone
31+
32+
# Recursively clone all neighbors
33+
for neighbor in node.neighbors:
34+
clone.neighbors.append(self.cloneGraph(neighbor))
35+
36+
return clone
37+
```
38+

python/design_browser_history.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# 1472. [Design Browser History](https://leetcode.com/problems/design-browser-history/)
2+
3+
## Approach: Doubly Linked List
4+
5+
### Solution
6+
python
7+
```python
8+
# Time Complexity:
9+
# - visit: O(1)
10+
# - back: O(steps)
11+
# - forward: O(steps)
12+
# Space Complexity: O(n), where n is the number of visited pages
13+
class Node:
14+
def __init__(self, url: str):
15+
self.url = url
16+
self.prev = None
17+
self.next = None
18+
19+
class BrowserHistory:
20+
def __init__(self, homepage: str):
21+
self.current = Node(homepage)
22+
23+
def visit(self, url: str) -> None:
24+
new_node = Node(url)
25+
self.current.next = new_node
26+
new_node.prev = self.current
27+
self.current = new_node # Move to the newly visited page
28+
29+
def back(self, steps: int) -> str:
30+
while steps > 0 and self.current.prev is not None:
31+
self.current = self.current.prev
32+
steps -= 1
33+
return self.current.url
34+
35+
def forward(self, steps: int) -> str:
36+
while steps > 0 and self.current.next is not None:
37+
self.current = self.current.next
38+
steps -= 1
39+
return self.current.url
40+
41+
# Example usage:
42+
# obj = BrowserHistory(homepage)
43+
# obj.visit(url)
44+
# param_2 = obj.back(steps)
45+
# param_3 = obj.forward(steps)
46+
```
47+

python/distinct_subsequences.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# 115. [Distinct Subsequences](https://leetcode.com/problems/distinct-subsequences/)
2+
3+
## Approach 1: Recursion with Memoization
4+
5+
### Solution
6+
python
7+
```python
8+
# Time Complexity: O(n * m)
9+
# Space Complexity: O(n * m)
10+
class Solution:
11+
def numDistinct(self, s: str, t: str) -> int:
12+
# Memoization table
13+
memo = [[-1 for _ in range(len(t))] for _ in range(len(s))]
14+
return self.numDistinctHelper(s, t, 0, 0, memo)
15+
16+
def numDistinctHelper(self, s: str, t: str, sIndex: int, tIndex: int, memo: list) -> int:
17+
# If t is exhausted, one subsequence is found
18+
if tIndex == len(t):
19+
return 1
20+
# If s is exhausted first, no subsequence can be formed
21+
if sIndex == len(s):
22+
return 0
23+
# Check memoization table
24+
if memo[sIndex][tIndex] != -1:
25+
return memo[sIndex][tIndex]
26+
27+
# If characters match, both decisions can be made
28+
if s[sIndex] == t[tIndex]:
29+
memo[sIndex][tIndex] = self.numDistinctHelper(s, t, sIndex + 1, tIndex + 1, memo) + \
30+
self.numDistinctHelper(s, t, sIndex + 1, tIndex, memo)
31+
else:
32+
# If characters don't match, skip the current character in s
33+
memo[sIndex][tIndex] = self.numDistinctHelper(s, t, sIndex + 1, tIndex, memo)
34+
35+
return memo[sIndex][tIndex]
36+
```
37+
38+
## Approach 2: Dynamic Programming
39+
40+
### Solution
41+
python
42+
```python
43+
# Time Complexity: O(n * m)
44+
# Space Complexity: O(n * m)
45+
class Solution:
46+
def numDistinct(self, s: str, t: str) -> int:
47+
# DP table
48+
dp = [[0] * (len(t) + 1) for _ in range(len(s) + 1)]
49+
50+
# Base case: empty t can be formed by all possible substrings of s
51+
for i in range(len(s) + 1):
52+
dp[i][len(t)] = 1
53+
54+
# Fill the table in reverse order
55+
for i in range(len(s) - 1, -1, -1):
56+
for j in range(len(t) - 1, -1, -1):
57+
if s[i] == t[j]:
58+
# Both using the character and ignoring it
59+
dp[i][j] = dp[i + 1][j + 1] + dp[i + 1][j]
60+
else:
61+
# Ignore the character in s
62+
dp[i][j] = dp[i + 1][j]
63+
64+
# Result is the number of ways to form t[0...m] from s[0...n]
65+
return dp[0][0]
66+
```
67+
68+
## Approach 3: Dynamic Programming with Space Optimization
69+
70+
### Solution
71+
python
72+
```python
73+
# Time Complexity: O(n * m)
74+
# Space Complexity: O(m)
75+
class Solution:
76+
def numDistinct(self, s: str, t: str) -> int:
77+
# Previous and current row for space optimization
78+
prev = [0] * (len(t) + 1)
79+
curr = [0] * (len(t) + 1)
80+
81+
# Base case: empty t can be formed by all possible substrings of s
82+
for i in range(len(s) + 1):
83+
prev[len(t)] = 1
84+
85+
# Fill the table in reverse order
86+
for i in range(len(s) - 1, -1, -1):
87+
for j in range(len(t) - 1, -1, -1):
88+
if s[i] == t[j]:
89+
curr[j] = prev[j + 1] + prev[j]
90+
else:
91+
curr[j] = prev[j]
92+
# Move current row to previous for next iteration
93+
prev = curr[:]
94+
95+
# Result is the number of ways to form t[0...m] from s[0...n]
96+
return prev[0]
97+
```
98+

python/house_robber.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# 198. [House Robber](https://leetcode.com/problems/house-robber/)
2+
3+
## Approach 1: Recursive Solution
4+
5+
### Solution
6+
```python
7+
# Time Complexity: O(2^n)
8+
# Space Complexity: O(n)
9+
class Solution:
10+
def rob(self, nums):
11+
return self.robFrom(0, nums)
12+
13+
def robFrom(self, index, nums):
14+
# Base case: If index is out of bounds, return 0
15+
if index >= len(nums):
16+
return 0
17+
18+
# Either rob this house and skip one, or skip it
19+
robCurrent = nums[index] + self.robFrom(index + 2, nums)
20+
skipCurrent = self.robFrom(index + 1, nums)
21+
22+
# Return the maximum of both choices
23+
return max(robCurrent, skipCurrent)
24+
```
25+
26+
## Approach 2: Recursion with Memoization
27+
28+
### Solution
29+
```python
30+
# Time Complexity: O(n)
31+
# Space Complexity: O(n)
32+
class Solution:
33+
def rob(self, nums):
34+
return self.robFrom(0, nums, {})
35+
36+
def robFrom(self, index, nums, memo):
37+
# Base case: If index is out of bounds, return 0
38+
if index >= len(nums):
39+
return 0
40+
41+
# Check memoization table
42+
if index in memo:
43+
return memo[index]
44+
45+
# Either rob this house and skip one, or skip it
46+
robCurrent = nums[index] + self.robFrom(index + 2, nums, memo)
47+
skipCurrent = self.robFrom(index + 1, nums, memo)
48+
49+
# Memoize the result
50+
result = max(robCurrent, skipCurrent)
51+
memo[index] = result
52+
53+
return result
54+
```
55+
56+
## Approach 3: Dynamic Programming (Bottom Up)
57+
58+
### Solution
59+
```python
60+
# Time Complexity: O(n)
61+
# Space Complexity: O(n)
62+
class Solution:
63+
def rob(self, nums):
64+
if not nums:
65+
return 0
66+
67+
dp = [0] * (len(nums) + 1)
68+
dp[0] = 0
69+
dp[1] = nums[0]
70+
71+
# Build the dp array
72+
for i in range(2, len(nums) + 1):
73+
dp[i] = max(dp[i - 1], dp[i - 2] + nums[i - 1])
74+
75+
return dp[len(nums)]
76+
```
77+
78+
## Approach 4: Optimized Dynamic Programming (Constant Space)
79+
80+
### Solution
81+
```python
82+
# Time Complexity: O(n)
83+
# Space Complexity: O(1)
84+
class Solution:
85+
def rob(self, nums):
86+
if not nums:
87+
return 0
88+
89+
prev1 = 0 # max money can rob up to the previous house
90+
prev2 = 0 # max money can rob up to two houses before
91+
92+
# Iterate through each house
93+
for num in nums:
94+
temp = prev1
95+
prev1 = max(prev2 + num, prev1)
96+
prev2 = temp
97+
98+
return prev1
99+
```
100+

0 commit comments

Comments
 (0)