Skip to content

2025/04/05 #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions Hard/815 Bus Routes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# 815 Bus Routes

## Intuition

The problem can be modeled as a graph where:

- Each bus route represents a set of connected stops
- We need to find the minimum number of bus changes required to go from source to target
- We can use BFS to explore all possible routes level by level, where each level represents one bus change

## Approach

1. First check if source and target are the same (return 0 if true)
2. Create a map `stopToBus` to store which buses stop at each station
3. Use BFS to explore all possible routes:
- Start from the source stop
- For each stop, check all buses that pass through it
- For each bus, check all stops it can reach
- If we reach the target, return the current number of bus changes
- Keep track of visited stops and buses to avoid cycles
4. If we exhaust all possibilities without finding the target, return -1

## Complexity

- Time complexity: O(N + M), where N is the number of stops and M is the number of bus routes
- Space complexity: O(N + M)

## Keywords

- BFS
- Graph

## Code

```go
func numBusesToDestination(routes [][]int, source int, target int) int {
if source == target {
return 0
}
ret, n, stopToBus := 0, 0, make(map[int][]int)
for i, route := range routes {
for _, stop := range route {
stopToBus[stop] = append(stopToBus[stop], i)
}
}

queue, stopRecord, busRecord := []int{source}, map[int]bool{source: true}, make(map[int]bool)
bfs := func(curStop int) bool {
for _, bus := range stopToBus[curStop] {
if busRecord[bus] {
continue
}
busRecord[bus] = true
for _, stop := range routes[bus] {
if stopRecord[stop] {
continue
}
if stop == target {
return true
}
queue, stopRecord[stop] = append(queue, stop), true
}
}
return false
}
for len(queue) != 0 {
ret, n = ret + 1, len(queue)
for _, curStop := range queue {
if bfs(curStop) {
return ret
}
}
queue = queue[n:]
}

return -1
}
```
75 changes: 75 additions & 0 deletions Medium/322 Coin Change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# 322. Coin Change

## Intuition

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.

## Approach

1. First, handle edge cases:
- If amount is 0, return 0
- If any coin equals the amount, return 1
- If all coins are larger than the amount, return -1
2. Initialize a DP array where dp[i] represents the minimum number of coins needed for amount i
3. Set initial values:
- dp[0] = 0 (0 coins needed for amount 0)
- All other values initialized to a large number (math.MaxInt - 1)
4. Sort the coins array for optimization
5. For each amount from 1 to target amount:
- For each coin denomination:
- If the coin is less than or equal to the current amount
- Update dp[i] with the minimum of current value and (dp[i - coin] + 1)
6. Return dp[amount] if it's not the initial large value, otherwise return -1

## Complexity

- Time complexity: O(n * m)
- Space complexity: O(n)

## Keywords

- Dynamic Programming
- Bottom-up Approach

## Code

```go
func coinChange(coins []int, amount int) int {
if amount == 0 {
return 0
}
smallFlag := false
for _, coin := range coins {
if coin == amount {
return 1
} else if coin < amount {
smallFlag = true
}
}
if !smallFlag {
return -1
}

dp := make([]int, amount + 1)
for i := range dp {
dp[i] = math.MaxInt - 1
}
dp[0] = 0

sort.Ints(coins)

for i := 1; i <= amount ; i += 1 {
for _, coin := range coins {
if coin <= i {
dp[i] = min(dp[i], dp[i - coin] + 1)
} else {
break
}
}
}
if dp[amount] == math.MaxInt - 1 {
return -1
}
return dp[amount]
}
```
102 changes: 102 additions & 0 deletions Medium/752 Open the Lock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# 752 Open the Lock

## Intuition

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.

## Approach

1. Start with the initial combination "0000"
2. Use BFS to explore all possible combinations:
- For each digit in the current combination, try turning it up and down
- Skip combinations that are in the deadends list
- Keep track of visited combinations to avoid cycles
- Return the number of steps when the target is found
3. If the queue becomes empty without finding the target, return -1

## Complexity

- Time complexity: O(N), where N is the number of possible combinations (10^4 = 10000)
- Space complexity: O(N)

## Keywords

- BFS
- Graph Traversal

## Code

```go
func openLock(deadends []string, target string) int {
if "0000" == target {
return 0
}
dds, record, ret := make(map[string]bool, len(deadends)), make(map[string]bool), 0
for _, dd := range deadends {
dds[dd] = true
}
if dds["0000"] {
return -1
}
record[target] = true

newCurProcess := func(i int, destDigit byte, cur string, tmp *[]string) bool {
curByte := []byte(cur)
curByte[i] = destDigit
cur = string(curByte)
if dds[cur] {
return false
}
if cur == target {
return true
}
if _, found := record[cur]; !found {
*tmp, record[cur] = append(*tmp, cur), true
}
return false
}

getNext := func(cur string, tmp *[]string) bool {
for i := 0; i < 4; i += 1 {
switch cur[i] {
case '0':
if newCurProcess(i, '1', cur, tmp) {
return true
}
if newCurProcess(i, '9', cur, tmp) {
return true
}
case '9':
if newCurProcess(i, '0', cur, tmp) {
return true
}
if newCurProcess(i, '8', cur, tmp) {
return true
}
default:
if newCurProcess(i, cur[i] + 1, cur, tmp) {
return true
}
if newCurProcess(i, cur[i] - 1, cur, tmp) {
return true
}
}
}
return false
}

queue := []string{"0000"}
for len(queue) != 0 {
ret += 1
tmp := make([]string, 0)
for _, cur := range queue {
if getNext(cur, &tmp) {
return ret
}
}
queue = tmp
}

return -1
}
```
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@
| 140 | Word Break II | [go](/Hard/140%20Word%20Break%20II.md) | H |
| 146 | LRU Cache | [go](/Medium/146%20LRU%20Cache.md) | M |
| 239 | Sliding Window Maximum | [go](/Hard/239%20Sliding%20Window%20Maximum.md) | H |
| 322 | Coin Change | [go](/Medium/322%20Coin%20Change.md) | M |
| 460 | LFU Cache | [go](/Hard/460%20LFU%20Cache.md) | H |
| 592 | Fraction Addition and Subtraction | [go](/Medium/592%20Fraction%20Addition%20and%20Subtraction.md) | M |
| 752 | Open the Lock | [go](/Medium/752%20Open%20the%20Lock.md) | M |
| 757 | Set Intersection Size At Least Two | [go](/Hard/757%20Set%20Intersection%20Size%20At%20Least%20Two.md) | H |
| 815 | Bus Routes | [go](/Hard/815%20Bus%20Routes.md) | H |
| 765 | Couples Holding Hands | [go](/Hard/765%20Couples%20Holding%20Hands.md) | H |
| 840 | Magic Squares In Grid | [go](/Medium/840%20Magic%20Squares%20In%20Grid.md) | M |
| 881 | Boats to Save People | [go](/Medium/881%20Boats%20to%20Save%20People.md) | M |
Expand Down
Binary file added Week7/322 AC.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
75 changes: 75 additions & 0 deletions Week7/322 Coin Change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# 322. Coin Change

## Intuition

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.

## Approach

1. First, handle edge cases:
- If amount is 0, return 0
- If any coin equals the amount, return 1
- If all coins are larger than the amount, return -1
2. Initialize a DP array where dp[i] represents the minimum number of coins needed for amount i
3. Set initial values:
- dp[0] = 0 (0 coins needed for amount 0)
- All other values initialized to a large number (math.MaxInt - 1)
4. Sort the coins array for optimization
5. For each amount from 1 to target amount:
- For each coin denomination:
- If the coin is less than or equal to the current amount
- Update dp[i] with the minimum of current value and (dp[i - coin] + 1)
6. Return dp[amount] if it's not the initial large value, otherwise return -1

## Complexity

- Time complexity: O(n * m)
- Space complexity: O(n)

## Keywords

- Dynamic Programming
- Bottom-up Approach

## Code

```go
func coinChange(coins []int, amount int) int {
if amount == 0 {
return 0
}
smallFlag := false
for _, coin := range coins {
if coin == amount {
return 1
} else if coin < amount {
smallFlag = true
}
}
if !smallFlag {
return -1
}

dp := make([]int, amount + 1)
for i := range dp {
dp[i] = math.MaxInt - 1
}
dp[0] = 0

sort.Ints(coins)

for i := 1; i <= amount ; i += 1 {
for _, coin := range coins {
if coin <= i {
dp[i] = min(dp[i], dp[i - coin] + 1)
} else {
break
}
}
}
if dp[amount] == math.MaxInt - 1 {
return -1
}
return dp[amount]
}
```
Binary file added Week7/752 AC.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading