Skip to content

Commit dd6ef3b

Browse files
authored
Merge pull request #12 from Alonza0314/2025/04/25
2025/04/25
2 parents c20f101 + 0d3daec commit dd6ef3b

10 files changed

+475
-0
lines changed

Hard/685 Redundant Connection II.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# 685. Redundant Connection II
2+
3+
## Intuition
4+
5+
The problem requires us to find a redundant edge in a directed graph that causes either a cycle or a node with two parents. The key insight is that there are two possible cases:
6+
7+
1. A node has two parents (in-degree > 1)
8+
2. The graph contains a cycle
9+
10+
## Approach
11+
12+
1. First, we identify if there's a node with two parents by tracking the parent of each node. If found, we store the two candidate edges.
13+
2. We use Union-Find (Disjoint Set Union) to detect cycles in the graph.
14+
3. We process all edges except the second candidate edge (if it exists).
15+
4. If we find a cycle:
16+
- If we had a node with two parents, return the first candidate edge
17+
- Otherwise, return the current edge that forms the cycle
18+
5. If no cycle is found, return the second candidate edge (which must be the redundant one)
19+
20+
## Complexity
21+
22+
- Time complexity: O(n)
23+
- Space complexity: O(n)
24+
25+
## Keywords
26+
27+
- Union-Find
28+
- Graph
29+
- Cycle Detection
30+
31+
## Code
32+
33+
```go
34+
func findRedundantDirectedConnection(edges [][]int) []int {
35+
parent, candidate1, candidate2 := make(map[int]int), -1, -1
36+
for i, edge := range edges {
37+
if ii, found := parent[edge[1]]; found {
38+
candidate1, candidate2 = ii, i
39+
break
40+
}
41+
parent[edge[1]] = i
42+
}
43+
44+
root := make([]int, len(edges) + 1)
45+
for i := range root {
46+
root[i] = i
47+
}
48+
49+
findRoot := func(n int) int {
50+
for root[n] != n {
51+
root[n] = root[root[n]]
52+
n = root[n]
53+
}
54+
return n
55+
}
56+
57+
for _, edge := range edges {
58+
u, v := edge[0], edge[1]
59+
if candidate2 != -1 && u == edges[candidate2][0] && v == edges[candidate2][1] {
60+
continue
61+
}
62+
63+
ur, uv := findRoot(u), findRoot(v)
64+
65+
if ur == uv {
66+
if candidate1 != -1 {
67+
return edges[candidate1]
68+
}
69+
return edge
70+
}
71+
root[uv] = ur
72+
}
73+
74+
return edges[candidate2]
75+
}
76+
```
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# 847. Shortest Path Visiting All Nodes
2+
3+
## Intuition
4+
5+
The problem requires finding the shortest path that visits all nodes in an undirected graph. We can think of this as a state-based BFS problem where each state consists of:
6+
7+
1. The current node we're at
8+
2. A bitmask representing which nodes we've visited so far
9+
10+
## Approach
11+
12+
1. Use BFS to explore all possible paths while keeping track of visited states
13+
2. Each state is represented by a combination of:
14+
- Current node position
15+
- Bitmask indicating visited nodes (1 << i for node i)
16+
3. Initialize the queue with all possible starting nodes
17+
4. For each state, explore all neighboring nodes
18+
5. Use a visited map to avoid revisiting the same state
19+
6. The target is reached when all nodes are visited (bitmask equals 2^n - 1)
20+
21+
## Complexity
22+
23+
- Time complexity: O(n * 2^n)
24+
- Space complexity: O(n * 2^n)
25+
26+
## Keywords
27+
28+
- BFS
29+
- Bitmask
30+
- State-based Search
31+
- Graph Traversal
32+
- Shortest Path
33+
34+
## Code
35+
36+
```go
37+
func shortestPathLength(graph [][]int) int {
38+
if len(graph) == 1 {
39+
return 0
40+
}
41+
42+
type unit struct {
43+
n int
44+
mask int
45+
}
46+
newUnit := func(i, m int) *unit {
47+
return &unit{
48+
n: i,
49+
mask: m,
50+
}
51+
}
52+
53+
visited := make([]map[int]bool, len(graph))
54+
queue := make([]*unit, 0)
55+
for i := range graph {
56+
mask := 1 << i
57+
visited[i] = make(map[int]bool)
58+
queue = append(queue, newUnit(i, mask))
59+
}
60+
61+
target, ret := 1 << len(graph) - 1, 1
62+
for {
63+
n := len(queue)
64+
for _, cur := range queue {
65+
for _, nb := range graph[cur.n] {
66+
nextMask := cur.mask | (1 << nb)
67+
if !visited[nb][nextMask] {
68+
if nextMask == target {
69+
goto RETURN
70+
}
71+
visited[nb][nextMask], queue = true, append(queue, newUnit(nb, nextMask))
72+
}
73+
}
74+
}
75+
queue, ret = queue[n:], ret + 1
76+
}
77+
78+
RETURN:
79+
return ret
80+
}
81+
```

Medium/210 Course Schedule II.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# 210. Course Schedule II
2+
3+
## Intuition
4+
5+
The problem is essentially about finding a valid topological order of courses given their prerequisites. We need to determine if it's possible to complete all courses and return the order in which they should be taken. This is a classic topological sorting problem where we need to find a linear ordering of vertices such that for every directed edge (u, v), vertex u comes before v in the ordering.
6+
7+
## Approach
8+
9+
1. Create a graph representation using an adjacency list and track the in-degree (number of prerequisites) for each course
10+
2. Initialize a queue with courses that have no prerequisites (in-degree = 0)
11+
3. Perform a BFS-like traversal:
12+
- Remove a course from the queue and add it to the result
13+
- For each course that has this course as a prerequisite, decrease their in-degree
14+
- If a course's in-degree becomes 0, add it to the queue
15+
4. If the length of the result equals the total number of courses, return the result; otherwise, return an empty array indicating it's impossible to complete all courses
16+
17+
## Complexity
18+
19+
- Time complexity: O(V + E)
20+
- Space complexity: O(V + E)
21+
22+
## Keywords
23+
24+
- Topological Sort
25+
- Graph
26+
- BFS
27+
28+
## Code
29+
30+
```go
31+
func findOrder(numCourses int, prerequisites [][]int) []int {
32+
type node struct {
33+
ingress int
34+
used bool
35+
neighbor []int
36+
}
37+
38+
ret, record := make([]int, 0), make([]node, numCourses)
39+
40+
for _, pre := range prerequisites {
41+
a, b := pre[0], pre[1]
42+
if !record[b].used {
43+
record[b].neighbor = make([]int, 0)
44+
}
45+
record[a].used, record[b].used = true, true
46+
record[a].ingress, record[b].neighbor = record[a].ingress + 1, append(record[b].neighbor, a)
47+
}
48+
49+
current := make([]int, 0)
50+
for i, n := range record {
51+
if !n.used {
52+
ret = append(ret, i)
53+
continue
54+
}
55+
if n.ingress == 0 {
56+
current = append(current, i)
57+
}
58+
}
59+
60+
for len(current) != 0 {
61+
ret = append(ret, current...)
62+
n := len(current)
63+
for _, num := range current {
64+
for _, nb := range record[num].neighbor {
65+
record[nb].ingress -= 1
66+
if record[nb].ingress == 0 {
67+
current = append(current, nb)
68+
}
69+
}
70+
}
71+
current = current[n:]
72+
}
73+
74+
if len(ret) != numCourses {
75+
return []int{}
76+
}
77+
return ret
78+
}
79+
```

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,19 @@
2424
| 135 | Candy | [go](/Hard/135%20Candy.md) | H |
2525
| 140 | Word Break II | [go](/Hard/140%20Word%20Break%20II.md) | H |
2626
| 146 | LRU Cache | [go](/Medium/146%20LRU%20Cache.md) | M |
27+
| 210 | Course Schedule II | [go](/Medium/210%20Course%20Schedule%20II.md) | M |
2728
| 236 | Lowest Common Ancestor of a Binary Tree | [go](/Medium/236%20Lowest%20Common%20Ancestor%20of%20a%20Binary%20Tree.md) | M |
2829
| 239 | Sliding Window Maximum | [go](/Hard/239%20Sliding%20Window%20Maximum.md) | H |
2930
| 322 | Coin Change | [go](/Medium/322%20Coin%20Change.md) | M |
3031
| 416 | Partition Equal Subset Sum | [go](/Medium/416%20Partition%20Equal%20Subset%20Sum.md) | M |
3132
| 435 | Non-overlapping Interval | [go](/Medium/435%20Non-overlapping%20Intervals.md) | M |
3233
| 460 | LFU Cache | [go](/Hard/460%20LFU%20Cache.md) | H |
3334
| 592 | Fraction Addition and Subtraction | [go](/Medium/592%20Fraction%20Addition%20and%20Subtraction.md) | M |
35+
| 685 | Redundant Connection II | [go](/Hard/685%20Redundant%20Connection%20II.md) | H |
3436
| 752 | Open the Lock | [go](/Medium/752%20Open%20the%20Lock.md) | M |
3537
| 757 | Set Intersection Size At Least Two | [go](/Hard/757%20Set%20Intersection%20Size%20At%20Least%20Two.md) | H |
3638
| 815 | Bus Routes | [go](/Hard/815%20Bus%20Routes.md) | H |
39+
| 847 | Shortest Path Visiting All Nodes | [go](/Hard/847%20Shortest%20Path%20Visiting%20All%20Nodes.md) | H |
3740
| 765 | Couples Holding Hands | [go](/Hard/765%20Couples%20Holding%20Hands.md) | H |
3841
| 834 | Sum of Distances in Tree | [go](/Hard/834%20Sum%20of%20Distances%20in%20Tree.md) | H |
3942
| 840 | Magic Squares In Grid | [go](/Medium/840%20Magic%20Squares%20In%20Grid.md) | M |

Week10/210 AC.png

41.5 KB
Loading

Week10/210 Course Schedule II.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# 210. Course Schedule II
2+
3+
## Intuition
4+
5+
The problem is essentially about finding a valid topological order of courses given their prerequisites. We need to determine if it's possible to complete all courses and return the order in which they should be taken. This is a classic topological sorting problem where we need to find a linear ordering of vertices such that for every directed edge (u, v), vertex u comes before v in the ordering.
6+
7+
## Approach
8+
9+
1. Create a graph representation using an adjacency list and track the in-degree (number of prerequisites) for each course
10+
2. Initialize a queue with courses that have no prerequisites (in-degree = 0)
11+
3. Perform a BFS-like traversal:
12+
- Remove a course from the queue and add it to the result
13+
- For each course that has this course as a prerequisite, decrease their in-degree
14+
- If a course's in-degree becomes 0, add it to the queue
15+
4. If the length of the result equals the total number of courses, return the result; otherwise, return an empty array indicating it's impossible to complete all courses
16+
17+
## Complexity
18+
19+
- Time complexity: O(V + E)
20+
- Space complexity: O(V + E)
21+
22+
## Keywords
23+
24+
- Topological Sort
25+
- Graph
26+
- BFS
27+
28+
## Code
29+
30+
```go
31+
func findOrder(numCourses int, prerequisites [][]int) []int {
32+
type node struct {
33+
ingress int
34+
used bool
35+
neighbor []int
36+
}
37+
38+
ret, record := make([]int, 0), make([]node, numCourses)
39+
40+
for _, pre := range prerequisites {
41+
a, b := pre[0], pre[1]
42+
if !record[b].used {
43+
record[b].neighbor = make([]int, 0)
44+
}
45+
record[a].used, record[b].used = true, true
46+
record[a].ingress, record[b].neighbor = record[a].ingress + 1, append(record[b].neighbor, a)
47+
}
48+
49+
current := make([]int, 0)
50+
for i, n := range record {
51+
if !n.used {
52+
ret = append(ret, i)
53+
continue
54+
}
55+
if n.ingress == 0 {
56+
current = append(current, i)
57+
}
58+
}
59+
60+
for len(current) != 0 {
61+
ret = append(ret, current...)
62+
n := len(current)
63+
for _, num := range current {
64+
for _, nb := range record[num].neighbor {
65+
record[nb].ingress -= 1
66+
if record[nb].ingress == 0 {
67+
current = append(current, nb)
68+
}
69+
}
70+
}
71+
current = current[n:]
72+
}
73+
74+
if len(ret) != numCourses {
75+
return []int{}
76+
}
77+
return ret
78+
}
79+
```

Week10/685 AC.png

39.2 KB
Loading

0 commit comments

Comments
 (0)