Skip to content

Commit 8bd350a

Browse files
authored
Merge pull request #8 from Alonza0314/2025/04/05
2025/04/05
2 parents 1a60fce + fa8150c commit 8bd350a

10 files changed

+513
-0
lines changed

Hard/815 Bus Routes.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# 815 Bus Routes
2+
3+
## Intuition
4+
5+
The problem can be modeled as a graph where:
6+
7+
- Each bus route represents a set of connected stops
8+
- We need to find the minimum number of bus changes required to go from source to target
9+
- We can use BFS to explore all possible routes level by level, where each level represents one bus change
10+
11+
## Approach
12+
13+
1. First check if source and target are the same (return 0 if true)
14+
2. Create a map `stopToBus` to store which buses stop at each station
15+
3. Use BFS to explore all possible routes:
16+
- Start from the source stop
17+
- For each stop, check all buses that pass through it
18+
- For each bus, check all stops it can reach
19+
- If we reach the target, return the current number of bus changes
20+
- Keep track of visited stops and buses to avoid cycles
21+
4. If we exhaust all possibilities without finding the target, return -1
22+
23+
## Complexity
24+
25+
- Time complexity: O(N + M), where N is the number of stops and M is the number of bus routes
26+
- Space complexity: O(N + M)
27+
28+
## Keywords
29+
30+
- BFS
31+
- Graph
32+
33+
## Code
34+
35+
```go
36+
func numBusesToDestination(routes [][]int, source int, target int) int {
37+
if source == target {
38+
return 0
39+
}
40+
ret, n, stopToBus := 0, 0, make(map[int][]int)
41+
for i, route := range routes {
42+
for _, stop := range route {
43+
stopToBus[stop] = append(stopToBus[stop], i)
44+
}
45+
}
46+
47+
queue, stopRecord, busRecord := []int{source}, map[int]bool{source: true}, make(map[int]bool)
48+
bfs := func(curStop int) bool {
49+
for _, bus := range stopToBus[curStop] {
50+
if busRecord[bus] {
51+
continue
52+
}
53+
busRecord[bus] = true
54+
for _, stop := range routes[bus] {
55+
if stopRecord[stop] {
56+
continue
57+
}
58+
if stop == target {
59+
return true
60+
}
61+
queue, stopRecord[stop] = append(queue, stop), true
62+
}
63+
}
64+
return false
65+
}
66+
for len(queue) != 0 {
67+
ret, n = ret + 1, len(queue)
68+
for _, curStop := range queue {
69+
if bfs(curStop) {
70+
return ret
71+
}
72+
}
73+
queue = queue[n:]
74+
}
75+
76+
return -1
77+
}
78+
```

Medium/322 Coin Change.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# 322. Coin Change
2+
3+
## Intuition
4+
5+
We can use dynamic programming to solve this problem by breaking it down into smaller subproblems. For each amount from 1 to the target amount, we can calculate the minimum number of coins needed by considering all possible coin denominations.
6+
7+
## Approach
8+
9+
1. First, handle edge cases:
10+
- If amount is 0, return 0
11+
- If any coin equals the amount, return 1
12+
- If all coins are larger than the amount, return -1
13+
2. Initialize a DP array where dp[i] represents the minimum number of coins needed for amount i
14+
3. Set initial values:
15+
- dp[0] = 0 (0 coins needed for amount 0)
16+
- All other values initialized to a large number (math.MaxInt - 1)
17+
4. Sort the coins array for optimization
18+
5. For each amount from 1 to target amount:
19+
- For each coin denomination:
20+
- If the coin is less than or equal to the current amount
21+
- Update dp[i] with the minimum of current value and (dp[i - coin] + 1)
22+
6. Return dp[amount] if it's not the initial large value, otherwise return -1
23+
24+
## Complexity
25+
26+
- Time complexity: O(n * m)
27+
- Space complexity: O(n)
28+
29+
## Keywords
30+
31+
- Dynamic Programming
32+
- Bottom-up Approach
33+
34+
## Code
35+
36+
```go
37+
func coinChange(coins []int, amount int) int {
38+
if amount == 0 {
39+
return 0
40+
}
41+
smallFlag := false
42+
for _, coin := range coins {
43+
if coin == amount {
44+
return 1
45+
} else if coin < amount {
46+
smallFlag = true
47+
}
48+
}
49+
if !smallFlag {
50+
return -1
51+
}
52+
53+
dp := make([]int, amount + 1)
54+
for i := range dp {
55+
dp[i] = math.MaxInt - 1
56+
}
57+
dp[0] = 0
58+
59+
sort.Ints(coins)
60+
61+
for i := 1; i <= amount ; i += 1 {
62+
for _, coin := range coins {
63+
if coin <= i {
64+
dp[i] = min(dp[i], dp[i - coin] + 1)
65+
} else {
66+
break
67+
}
68+
}
69+
}
70+
if dp[amount] == math.MaxInt - 1 {
71+
return -1
72+
}
73+
return dp[amount]
74+
}
75+
```

Medium/752 Open the Lock.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# 752 Open the Lock
2+
3+
## Intuition
4+
5+
The problem can be modeled as a graph traversal problem where each node represents a lock combination (4-digit number) and edges represent valid moves (turning one wheel up or down). We need to find the shortest path from "0000" to the target combination while avoiding deadends. This naturally leads to using BFS (Breadth-First Search) as it guarantees finding the shortest path in an unweighted graph.
6+
7+
## Approach
8+
9+
1. Start with the initial combination "0000"
10+
2. Use BFS to explore all possible combinations:
11+
- For each digit in the current combination, try turning it up and down
12+
- Skip combinations that are in the deadends list
13+
- Keep track of visited combinations to avoid cycles
14+
- Return the number of steps when the target is found
15+
3. If the queue becomes empty without finding the target, return -1
16+
17+
## Complexity
18+
19+
- Time complexity: O(N), where N is the number of possible combinations (10^4 = 10000)
20+
- Space complexity: O(N)
21+
22+
## Keywords
23+
24+
- BFS
25+
- Graph Traversal
26+
27+
## Code
28+
29+
```go
30+
func openLock(deadends []string, target string) int {
31+
if "0000" == target {
32+
return 0
33+
}
34+
dds, record, ret := make(map[string]bool, len(deadends)), make(map[string]bool), 0
35+
for _, dd := range deadends {
36+
dds[dd] = true
37+
}
38+
if dds["0000"] {
39+
return -1
40+
}
41+
record[target] = true
42+
43+
newCurProcess := func(i int, destDigit byte, cur string, tmp *[]string) bool {
44+
curByte := []byte(cur)
45+
curByte[i] = destDigit
46+
cur = string(curByte)
47+
if dds[cur] {
48+
return false
49+
}
50+
if cur == target {
51+
return true
52+
}
53+
if _, found := record[cur]; !found {
54+
*tmp, record[cur] = append(*tmp, cur), true
55+
}
56+
return false
57+
}
58+
59+
getNext := func(cur string, tmp *[]string) bool {
60+
for i := 0; i < 4; i += 1 {
61+
switch cur[i] {
62+
case '0':
63+
if newCurProcess(i, '1', cur, tmp) {
64+
return true
65+
}
66+
if newCurProcess(i, '9', cur, tmp) {
67+
return true
68+
}
69+
case '9':
70+
if newCurProcess(i, '0', cur, tmp) {
71+
return true
72+
}
73+
if newCurProcess(i, '8', cur, tmp) {
74+
return true
75+
}
76+
default:
77+
if newCurProcess(i, cur[i] + 1, cur, tmp) {
78+
return true
79+
}
80+
if newCurProcess(i, cur[i] - 1, cur, tmp) {
81+
return true
82+
}
83+
}
84+
}
85+
return false
86+
}
87+
88+
queue := []string{"0000"}
89+
for len(queue) != 0 {
90+
ret += 1
91+
tmp := make([]string, 0)
92+
for _, cur := range queue {
93+
if getNext(cur, &tmp) {
94+
return ret
95+
}
96+
}
97+
queue = tmp
98+
}
99+
100+
return -1
101+
}
102+
```

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@
2222
| 140 | Word Break II | [go](/Hard/140%20Word%20Break%20II.md) | H |
2323
| 146 | LRU Cache | [go](/Medium/146%20LRU%20Cache.md) | M |
2424
| 239 | Sliding Window Maximum | [go](/Hard/239%20Sliding%20Window%20Maximum.md) | H |
25+
| 322 | Coin Change | [go](/Medium/322%20Coin%20Change.md) | M |
2526
| 460 | LFU Cache | [go](/Hard/460%20LFU%20Cache.md) | H |
2627
| 592 | Fraction Addition and Subtraction | [go](/Medium/592%20Fraction%20Addition%20and%20Subtraction.md) | M |
28+
| 752 | Open the Lock | [go](/Medium/752%20Open%20the%20Lock.md) | M |
2729
| 757 | Set Intersection Size At Least Two | [go](/Hard/757%20Set%20Intersection%20Size%20At%20Least%20Two.md) | H |
30+
| 815 | Bus Routes | [go](/Hard/815%20Bus%20Routes.md) | H |
2831
| 765 | Couples Holding Hands | [go](/Hard/765%20Couples%20Holding%20Hands.md) | H |
2932
| 840 | Magic Squares In Grid | [go](/Medium/840%20Magic%20Squares%20In%20Grid.md) | M |
3033
| 881 | Boats to Save People | [go](/Medium/881%20Boats%20to%20Save%20People.md) | M |

Week7/322 AC.png

43 KB
Loading

Week7/322 Coin Change.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# 322. Coin Change
2+
3+
## Intuition
4+
5+
We can use dynamic programming to solve this problem by breaking it down into smaller subproblems. For each amount from 1 to the target amount, we can calculate the minimum number of coins needed by considering all possible coin denominations.
6+
7+
## Approach
8+
9+
1. First, handle edge cases:
10+
- If amount is 0, return 0
11+
- If any coin equals the amount, return 1
12+
- If all coins are larger than the amount, return -1
13+
2. Initialize a DP array where dp[i] represents the minimum number of coins needed for amount i
14+
3. Set initial values:
15+
- dp[0] = 0 (0 coins needed for amount 0)
16+
- All other values initialized to a large number (math.MaxInt - 1)
17+
4. Sort the coins array for optimization
18+
5. For each amount from 1 to target amount:
19+
- For each coin denomination:
20+
- If the coin is less than or equal to the current amount
21+
- Update dp[i] with the minimum of current value and (dp[i - coin] + 1)
22+
6. Return dp[amount] if it's not the initial large value, otherwise return -1
23+
24+
## Complexity
25+
26+
- Time complexity: O(n * m)
27+
- Space complexity: O(n)
28+
29+
## Keywords
30+
31+
- Dynamic Programming
32+
- Bottom-up Approach
33+
34+
## Code
35+
36+
```go
37+
func coinChange(coins []int, amount int) int {
38+
if amount == 0 {
39+
return 0
40+
}
41+
smallFlag := false
42+
for _, coin := range coins {
43+
if coin == amount {
44+
return 1
45+
} else if coin < amount {
46+
smallFlag = true
47+
}
48+
}
49+
if !smallFlag {
50+
return -1
51+
}
52+
53+
dp := make([]int, amount + 1)
54+
for i := range dp {
55+
dp[i] = math.MaxInt - 1
56+
}
57+
dp[0] = 0
58+
59+
sort.Ints(coins)
60+
61+
for i := 1; i <= amount ; i += 1 {
62+
for _, coin := range coins {
63+
if coin <= i {
64+
dp[i] = min(dp[i], dp[i - coin] + 1)
65+
} else {
66+
break
67+
}
68+
}
69+
}
70+
if dp[amount] == math.MaxInt - 1 {
71+
return -1
72+
}
73+
return dp[amount]
74+
}
75+
```

Week7/752 AC.png

43.4 KB
Loading

0 commit comments

Comments
 (0)