mirror of
https://github.com/prdlk/leetcode.git
synced 2026-11-02 21:22:43 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0f479d6cf | ||
|
|
ac4dc654fc | ||
|
|
273148c08b | ||
|
|
7960dee431 |
No files matched your search
@@ -0,0 +1,53 @@
|
||||
---
|
||||
title: '39. Combination Sum'
|
||||
description: Given an array of distinct integers candidates and a target integer target, return a list of all unique combinations of candidates where the chosen numbers sum to target. You may return the combinations in any order
|
||||
sidebar:
|
||||
label: 'Combination Sum'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Array</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `candidates = [2,3,6,7], target = 7`
|
||||
- Output: `[[2,2,3],[7]]`
|
||||
- Explanation: `2` and `3` are `candidates`, and `2 + 2 + 3 = 7`. Note that `2` can be used multiple times. `7` is a candidate, and `7 = 7`. These are the only two combinations.
|
||||
|
||||
### Example 2:
|
||||
- Input: `candidates = [2,3,5], target = 8`
|
||||
- Output: `[[2,2,2,2],[2,3,3],[3,5]]`
|
||||
|
||||
### Example 3:
|
||||
- Input: `candidates = [2], target = 1`
|
||||
- Output: `[]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= candidates.length <= 30`
|
||||
- `2 <= candidates[i] <= 40`
|
||||
- All elements of `candidates` are distinct.
|
||||
- `1 <= target <= 40`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def combinationSum(self, candidates: list[int], target: int) -> list[list[int]]:
|
||||
candidates.sort()
|
||||
result, path = [], []
|
||||
|
||||
def backtrack(start, remaining):
|
||||
if remaining == 0:
|
||||
result.append(path[:])
|
||||
return
|
||||
for i in range(start, len(candidates)):
|
||||
if candidates[i] > remaining:
|
||||
break
|
||||
|
||||
path.append(candidates[i])
|
||||
backtrack(i, remaining - candidates[i])
|
||||
path.pop()
|
||||
|
||||
backtrack(0, target)
|
||||
return result
|
||||
```
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
title: '46. Permutations'
|
||||
description: Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order
|
||||
sidebar:
|
||||
label: 'Permutations'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Array</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,2,3]`
|
||||
- Output: `[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [0,1]`
|
||||
- Output: `[[0,1],[1,0]]`
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [1]`
|
||||
- Output: `[[1]]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 6`
|
||||
- `-10 <= nums[i] <= 10`
|
||||
- All the integers of `nums` are unique.
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def permute(self, nums: list[int]) -> list[list[int]]:
|
||||
result, path = [], []
|
||||
used = [False] * len(nums)
|
||||
|
||||
def backtrack():
|
||||
if len(path) == len(nums):
|
||||
result.append(path[:])
|
||||
return
|
||||
for i in range(len(nums)):
|
||||
if used[i]:
|
||||
continue
|
||||
used[i] = True
|
||||
path.append(nums[i])
|
||||
backtrack()
|
||||
path.pop()
|
||||
used[i] = False
|
||||
|
||||
backtrack()
|
||||
return result
|
||||
```
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
title: '78. Subsets'
|
||||
description: Given an integer array nums of unique elements, return all possible subsets (the power set)
|
||||
sidebar:
|
||||
label: 'Subsets'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Array</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,2,3]`
|
||||
- Output: `[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [0]`
|
||||
- Output: `[[],[0]]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10`
|
||||
- `-10 <= nums[i] <= 10`
|
||||
- All the numbers of `nums` are unique.
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def subsets(self, nums: list[int]) -> list[list[int]]:
|
||||
res = []
|
||||
|
||||
def backtrack(i, path):
|
||||
res.append(path[:])
|
||||
for num_idx in range(i, len(nums)):
|
||||
path.append(nums[num_idx])
|
||||
backtrack(num_idx + 1, path)
|
||||
path.pop()
|
||||
|
||||
backtrack(0, [])
|
||||
return res
|
||||
```
|
||||
@@ -0,0 +1,163 @@
|
||||
---
|
||||
title: Backtracking
|
||||
description: 'Backtracking is a depth-first search technique that builds a solution step by step and abandons (undoes) a partial choice as soon as it can’t lead to a valid complete solution.'
|
||||
hidden: true
|
||||
---
|
||||
|
||||
## What it is
|
||||
|
||||
Backtracking explores possible paths to a solution one step at a time. When a path reaches a dead end, you undo the last step and try a different option. Think of every problem as a decision tree. The root is an empty answer. Each level is a decision. Each branch is one option.
|
||||
|
||||
## When to use it
|
||||
|
||||
Use backtracking when you must generate **all** valid solutions or evaluate **all** combinations. Do not use it when you need only one solution or the optimal solution. For those, use greedy or dynamic programming. Backtracking has exponential time complexity.
|
||||
|
||||
## The four components
|
||||
|
||||
Every backtracking problem has the same parts:
|
||||
|
||||
1. **Base case** — when to save the current path and stop.
|
||||
2. **Choices** — the options at each step.
|
||||
3. **Constraints** — the rules that reject an invalid path early.
|
||||
4. **Backtrack step** — undo the last choice and try the next one.
|
||||
|
||||
## The template
|
||||
|
||||
```python
|
||||
def solve(data):
|
||||
result = []
|
||||
path = []
|
||||
|
||||
def backtrack(index):
|
||||
# 1. Base case
|
||||
if is_complete(index, path):
|
||||
result.append(path[:]) # copy — lists are passed by reference
|
||||
return
|
||||
|
||||
# 2. Choices
|
||||
for choice in get_choices(index, data):
|
||||
# 3. Constraints
|
||||
if not is_valid(choice, path):
|
||||
continue
|
||||
|
||||
path.append(choice) # make the choice
|
||||
backtrack(index + 1) # explore
|
||||
path.pop() # 4. Backtrack
|
||||
|
||||
backtrack(0)
|
||||
return result
|
||||
```
|
||||
|
||||
## Steps to apply the template
|
||||
|
||||
1. Draw the decision tree for a small input. Name each level and each branch.
|
||||
2. Write the base case. Ask: when is the path complete?
|
||||
3. Write the choices. Ask: what can I add at this level?
|
||||
4. Write the constraints. Ask: what makes a path invalid? Reject it before recursion.
|
||||
5. Add the backtrack step. Pop what you appended.
|
||||
6. Copy the path when you save it. Never append the same list reference.
|
||||
|
||||
## Four problems, one template
|
||||
|
||||
### Subsets
|
||||
|
||||
Choice: include or skip each number. No constraint. Base case: index equals list length.
|
||||
|
||||
```python
|
||||
def subsets(nums):
|
||||
result, path = [], []
|
||||
|
||||
def backtrack(i):
|
||||
if i == len(nums):
|
||||
result.append(path[:])
|
||||
return
|
||||
path.append(nums[i]) # include
|
||||
backtrack(i + 1)
|
||||
path.pop()
|
||||
backtrack(i + 1) # skip
|
||||
|
||||
backtrack(0)
|
||||
return result
|
||||
```
|
||||
|
||||
### Permutations
|
||||
|
||||
Same choices as subsets. Constraint: do not reuse a number already in the path. Base case: path length equals list length.
|
||||
|
||||
```python
|
||||
def permute(nums):
|
||||
result, path = [], []
|
||||
used = [False] * len(nums)
|
||||
|
||||
def backtrack():
|
||||
if len(path) == len(nums):
|
||||
result.append(path[:])
|
||||
return
|
||||
for i in range(len(nums)):
|
||||
if used[i]:
|
||||
continue
|
||||
used[i] = True
|
||||
path.append(nums[i])
|
||||
backtrack()
|
||||
path.pop()
|
||||
used[i] = False
|
||||
|
||||
backtrack()
|
||||
return result
|
||||
```
|
||||
|
||||
### Combinations
|
||||
|
||||
Same as subsets. Change one line: save the path only when its length equals `k`.
|
||||
|
||||
```python
|
||||
def combine(n, k):
|
||||
result, path = [], []
|
||||
|
||||
def backtrack(start):
|
||||
if len(path) == k:
|
||||
result.append(path[:])
|
||||
return
|
||||
for i in range(start, n + 1):
|
||||
path.append(i)
|
||||
backtrack(i + 1)
|
||||
path.pop()
|
||||
|
||||
backtrack(1)
|
||||
return result
|
||||
```
|
||||
|
||||
### N-Queens
|
||||
|
||||
Choice: which column to place the queen in the current row. Constraint: no shared column or diagonal. Base case: `n` queens placed. Backtrack: remove the last queen.
|
||||
|
||||
```python
|
||||
def solve_n_queens(n):
|
||||
result, cols = [], []
|
||||
used_cols, diag1, diag2 = set(), set(), set()
|
||||
|
||||
def backtrack(row):
|
||||
if row == n:
|
||||
result.append(cols[:])
|
||||
return
|
||||
for col in range(n):
|
||||
if col in used_cols or row - col in diag1 or row + col in diag2:
|
||||
continue
|
||||
cols.append(col)
|
||||
used_cols.add(col); diag1.add(row - col); diag2.add(row + col)
|
||||
backtrack(row + 1)
|
||||
cols.pop()
|
||||
used_cols.remove(col); diag1.remove(row - col); diag2.remove(row + col)
|
||||
|
||||
backtrack(0)
|
||||
return result
|
||||
```
|
||||
|
||||
## Common mistakes
|
||||
|
||||
- You append the `path` list itself instead of a copy. The result fills with empty lists.
|
||||
- You forget to pop. The path grows and never resets.
|
||||
- You check constraints after recursion instead of before. You waste time on dead paths.
|
||||
- You use backtracking when you need only one answer. Use greedy or DP instead.
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Backtracking", order: 20 });
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
---
|
||||
title: '323. Number of Connected Components in an Undirected Graph'
|
||||
description: You have a graph of n nodes. You are given an integer n and an array edges where edges[i] = [ai, bi] indicates that there is an edge between ai and bi in the graph
|
||||
sidebar:
|
||||
label: 'Number of Connected Components in an Undirected Graph'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Depth-First Search</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `n = 5, edges = [[0,1],[1,2],[3,4]]`
|
||||
- Output: `2`
|
||||
|
||||
### Example 2:
|
||||
- Input: `n = 5, edges = [[0,1],[1,2],[2,3],[3,4]]`
|
||||
- Output: `1`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= n <= 2000`
|
||||
- `1 <= edges.length <= 5000`
|
||||
- `edges[i]` = [ai, bi]
|
||||
- `ai != bi`
|
||||
- There are no repeated edges.
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def countComponents(self, n: int, edges: list[list[int]]) -> int:
|
||||
par = [i for i in range(n + 1)]
|
||||
rank = [1] * (n + 1)
|
||||
|
||||
def find(n):
|
||||
res = n
|
||||
while res != par[res]:
|
||||
par[res] = par[par[res]]
|
||||
res = par[res]
|
||||
return res
|
||||
|
||||
def union(n1, n2):
|
||||
p1, p2 = find(n1), find(n2)
|
||||
if p1 == p2:
|
||||
return 0
|
||||
if rank[p1] > rank[p2]:
|
||||
par[p2] = p1
|
||||
rank[p1] += rank[p2]
|
||||
else:
|
||||
par[p1] = p2
|
||||
rank[p2] += rank[p1]
|
||||
return 1
|
||||
|
||||
res = n
|
||||
for n1, n2 in edges:
|
||||
res -= union(n1, n2)
|
||||
return res
|
||||
```
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
title: '684. Redundant Connection'
|
||||
description: In this problem, a tree is an undirected graph that is connected and has no cycles
|
||||
sidebar:
|
||||
label: 'Redundant Connection'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Depth-First Search</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `edges = [[1,2],[1,3],[2,3]]`
|
||||
- Output: `[2,3]`
|
||||
|
||||
### Example 2:
|
||||
- Input: `edges = [[1,2],[2,3],[3,4],[1,4],[1,5]]`
|
||||
- Output: `[1,4]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `n == edges.length`
|
||||
- `3 <= n <= 1000`
|
||||
- `edges[i].length == 2`
|
||||
- `1 <= ai < bi <= edges.length`
|
||||
- `ai != bi`
|
||||
- There are no repeated edges.
|
||||
- The given graph is connected.
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def findRedundantConnection(self, edges: list[list[int]]) -> list[int]:
|
||||
N = len(edges)
|
||||
par = [i for i in range(N + 1)]
|
||||
rank = [1] * (N + 1)
|
||||
|
||||
def find(n):
|
||||
if n != par[n]:
|
||||
par[n] = find(par[n])
|
||||
return par[n]
|
||||
|
||||
def union(n1, n2):
|
||||
p1, p2 = find(n1), find(n2)
|
||||
if p1 == p2:
|
||||
return False
|
||||
|
||||
if rank[p1] > rank[p2]:
|
||||
par[p2] = p1
|
||||
rank[p1] += rank[p2]
|
||||
else:
|
||||
par[p1] = p2
|
||||
rank[p2] += rank[p1]
|
||||
|
||||
return True
|
||||
|
||||
for n1, n2 in edges:
|
||||
if not union(n1, n2):
|
||||
return [n1, n2]
|
||||
```
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
title: Union Find
|
||||
description: 'Union-Find (Disjoint Set Union) is a data structure that maintains a collection of disjoint sets and supports efficiently finding which set an element belongs to and merging two sets.'
|
||||
hidden: true
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Union-Find", order: 19 });
|
||||
@@ -176,8 +176,8 @@ const topicRoutes = (nav: unknown): Record<string, string> => {
|
||||
// ── component ────────────────────────────────────────────────────
|
||||
|
||||
interface ViewBox { x: number; y: number; w: number; h: number }
|
||||
/** The resting view — 2× on the centre so node labels read at the content width; 1× stays reachable by zooming out. */
|
||||
const HOME_ZOOM = 2;
|
||||
/** The resting view — 1.6× on the centre so node labels read at the content width; 1× stays reachable by zooming out. */
|
||||
const HOME_ZOOM = 1.6;
|
||||
const HOME: ViewBox = { x: (W - W / HOME_ZOOM) / 2, y: (H - H / HOME_ZOOM) / 2, w: W / HOME_ZOOM, h: H / HOME_ZOOM };
|
||||
const clamp = (v: number, lo: number, hi: number) => Math.min(Math.max(v, lo), hi);
|
||||
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
39. Combination Sum
|
||||
Difficulty: Medium
|
||||
https://leetcode.com/problems/combination-sum/
|
||||
|
||||
──────────────────────────────────────────────────
|
||||
|
||||
Given an array of distinct integers candidates and a target integer
|
||||
target, return a list of all unique combinations of candidates where
|
||||
the chosen numbers sum to target. You may return the combinations in
|
||||
any order.
|
||||
|
||||
The same number may be chosen from candidates an unlimited number of
|
||||
times. Two combinations are unique if the frequency of at least one of
|
||||
the chosen numbers is different.
|
||||
|
||||
The test cases are generated such that the number of unique
|
||||
combinations that sum up to target is less than 150 combinations for
|
||||
the given input.
|
||||
|
||||
|
||||
|
||||
Example 1:
|
||||
|
||||
Input: candidates = [2,3,6,7], target = 7
|
||||
Output: [[2,2,3],[7]]
|
||||
Explanation:
|
||||
2 and 3 are candidates, and 2 + 2 + 3 = 7. Note that 2 can be used
|
||||
multiple times.
|
||||
7 is a candidate, and 7 = 7.
|
||||
These are the only two combinations.
|
||||
|
||||
Example 2:
|
||||
|
||||
Input: candidates = [2,3,5], target = 8
|
||||
Output: [[2,2,2,2],[2,3,3],[3,5]]
|
||||
|
||||
Example 3:
|
||||
|
||||
Input: candidates = [2], target = 1
|
||||
Output: []
|
||||
|
||||
|
||||
|
||||
Constraints:
|
||||
|
||||
• 1 <= candidates.length <= 30
|
||||
|
||||
• 2 <= candidates[i] <= 40
|
||||
|
||||
• All elements of candidates are distinct.
|
||||
|
||||
• 1 <= target <= 40
|
||||
"""
|
||||
|
||||
|
||||
class Solution:
|
||||
def combinationSum(self, candidates: list[int], target: int) -> list[list[int]]:
|
||||
candidates.sort()
|
||||
result, path = [], []
|
||||
|
||||
def backtrack(start, remaining):
|
||||
if remaining == 0:
|
||||
result.append(path[:])
|
||||
return
|
||||
for i in range(start, len(candidates)):
|
||||
if candidates[i] > remaining:
|
||||
break
|
||||
|
||||
path.append(candidates[i])
|
||||
backtrack(i, remaining - candidates[i])
|
||||
path.pop()
|
||||
|
||||
backtrack(0, target)
|
||||
return result
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
46. Permutations
|
||||
Difficulty: Medium
|
||||
https://leetcode.com/problems/permutations/
|
||||
|
||||
──────────────────────────────────────────────────
|
||||
|
||||
Given an array nums of distinct integers, return all the possible
|
||||
permutations. You can return the answer in any order.
|
||||
|
||||
|
||||
|
||||
Example 1:
|
||||
|
||||
Input: nums = [1,2,3]
|
||||
Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
|
||||
|
||||
Example 2:
|
||||
|
||||
Input: nums = [0,1]
|
||||
Output: [[0,1],[1,0]]
|
||||
|
||||
Example 3:
|
||||
|
||||
Input: nums = [1]
|
||||
Output: [[1]]
|
||||
|
||||
|
||||
|
||||
Constraints:
|
||||
|
||||
• 1 <= nums.length <= 6
|
||||
|
||||
• -10 <= nums[i] <= 10
|
||||
|
||||
• All the integers of nums are unique.
|
||||
"""
|
||||
|
||||
|
||||
class Solution:
|
||||
def permute(self, nums: list[int]) -> list[list[int]]:
|
||||
result, path = [], []
|
||||
used = [False] * len(nums)
|
||||
|
||||
def backtrack():
|
||||
if len(path) == len(nums):
|
||||
result.append(path[:])
|
||||
return
|
||||
for i in range(len(nums)):
|
||||
if used[i]:
|
||||
continue
|
||||
used[i] = True
|
||||
path.append(nums[i])
|
||||
backtrack()
|
||||
path.pop()
|
||||
used[i] = False
|
||||
|
||||
backtrack()
|
||||
return result
|
||||
@@ -0,0 +1,50 @@
|
||||
"""
|
||||
78. Subsets
|
||||
Difficulty: Medium
|
||||
https://leetcode.com/problems/subsets/
|
||||
|
||||
──────────────────────────────────────────────────
|
||||
|
||||
Given an integer array nums of unique elements, return all possible
|
||||
subsets (the power set).
|
||||
|
||||
The solution set must not contain duplicate subsets. Return the
|
||||
solution in any order.
|
||||
|
||||
|
||||
|
||||
Example 1:
|
||||
|
||||
Input: nums = [1,2,3]
|
||||
Output: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
|
||||
|
||||
Example 2:
|
||||
|
||||
Input: nums = [0]
|
||||
Output: [[],[0]]
|
||||
|
||||
|
||||
|
||||
Constraints:
|
||||
|
||||
• 1 <= nums.length <= 10
|
||||
|
||||
• -10 <= nums[i] <= 10
|
||||
|
||||
• All the numbers of nums are unique.
|
||||
"""
|
||||
|
||||
|
||||
class Solution:
|
||||
def subsets(self, nums: list[int]) -> list[list[int]]:
|
||||
res = []
|
||||
|
||||
def backtrack(i, path):
|
||||
res.append(path[:])
|
||||
for num_idx in range(i, len(nums)):
|
||||
path.append(nums[num_idx])
|
||||
backtrack(num_idx + 1, path)
|
||||
path.pop()
|
||||
|
||||
backtrack(0, [])
|
||||
return res
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
"""
|
||||
323. Number of Connected Components in an Undirected Graph
|
||||
Difficulty: Medium
|
||||
https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/
|
||||
|
||||
──────────────────────────────────────────────────
|
||||
|
||||
You have a graph of n nodes. You are given an integer n and an array
|
||||
edges where edges[i] = [ai, bi] indicates that there is an edge
|
||||
between ai and bi in the graph.
|
||||
|
||||
Return the number of connected components in the graph.
|
||||
|
||||
|
||||
|
||||
Example 1:
|
||||
|
||||
Input: n = 5, edges = [[0,1],[1,2],[3,4]]
|
||||
Output: 2
|
||||
|
||||
Example 2:
|
||||
|
||||
Input: n = 5, edges = [[0,1],[1,2],[2,3],[3,4]]
|
||||
Output: 1
|
||||
|
||||
|
||||
|
||||
Constraints:
|
||||
|
||||
• 1 <= n <= 2000
|
||||
|
||||
• 1 <= edges.length <= 5000
|
||||
|
||||
• edges[i] = [ai, bi]
|
||||
|
||||
• ai != bi
|
||||
|
||||
• There are no repeated edges.
|
||||
"""
|
||||
|
||||
|
||||
class Solution:
|
||||
def countComponents(self, n: int, edges: list[list[int]]) -> int:
|
||||
par = [i for i in range(n + 1)]
|
||||
rank = [1] * (n + 1)
|
||||
|
||||
def find(n):
|
||||
res = n
|
||||
while res != par[res]:
|
||||
par[res] = par[par[res]]
|
||||
res = par[res]
|
||||
return res
|
||||
|
||||
def union(n1, n2):
|
||||
p1, p2 = find(n1), find(n2)
|
||||
if p1 == p2:
|
||||
return 0
|
||||
if rank[p1] > rank[p2]:
|
||||
par[p2] = p1
|
||||
rank[p1] += rank[p2]
|
||||
else:
|
||||
par[p1] = p2
|
||||
rank[p2] += rank[p1]
|
||||
return 1
|
||||
|
||||
res = n
|
||||
for n1, n2 in edges:
|
||||
res -= union(n1, n2)
|
||||
return res
|
||||
@@ -0,0 +1,81 @@
|
||||
"""
|
||||
684. Redundant Connection
|
||||
Difficulty: Medium
|
||||
https://leetcode.com/problems/redundant-connection/
|
||||
|
||||
──────────────────────────────────────────────────
|
||||
|
||||
In this problem, a tree is an undirected graph that is connected and
|
||||
has no cycles.
|
||||
|
||||
You are given a graph that started as a tree with n nodes labeled
|
||||
from 1 to n, with one additional edge added. The added edge has two
|
||||
different vertices chosen from 1 to n, and was not an edge that
|
||||
already existed. The graph is represented as an array edges of length
|
||||
n where edges[i] = [ai, bi] indicates that there is an edge between
|
||||
nodes ai and bi in the graph.
|
||||
|
||||
Return an edge that can be removed so that the resulting graph is a
|
||||
tree of n nodes. If there are multiple answers, return the answer that
|
||||
occurs last in the input.
|
||||
|
||||
|
||||
|
||||
Example 1:
|
||||
|
||||
Input: edges = [[1,2],[1,3],[2,3]]
|
||||
Output: [2,3]
|
||||
|
||||
Example 2:
|
||||
|
||||
Input: edges = [[1,2],[2,3],[3,4],[1,4],[1,5]]
|
||||
Output: [1,4]
|
||||
|
||||
|
||||
|
||||
Constraints:
|
||||
|
||||
• n == edges.length
|
||||
|
||||
• 3 <= n <= 1000
|
||||
|
||||
• edges[i].length == 2
|
||||
|
||||
• 1 <= ai < bi <= edges.length
|
||||
|
||||
• ai != bi
|
||||
|
||||
• There are no repeated edges.
|
||||
|
||||
• The given graph is connected.
|
||||
"""
|
||||
|
||||
|
||||
class Solution:
|
||||
def findRedundantConnection(self, edges: list[list[int]]) -> list[int]:
|
||||
N = len(edges)
|
||||
par = [i for i in range(N + 1)]
|
||||
rank = [1] * (N + 1)
|
||||
|
||||
def find(n):
|
||||
if n != par[n]:
|
||||
par[n] = find(par[n])
|
||||
return par[n]
|
||||
|
||||
def union(n1, n2):
|
||||
p1, p2 = find(n1), find(n2)
|
||||
if p1 == p2:
|
||||
return False
|
||||
|
||||
if rank[p1] > rank[p2]:
|
||||
par[p2] = p1
|
||||
rank[p1] += rank[p2]
|
||||
else:
|
||||
par[p1] = p2
|
||||
rank[p2] += rank[p1]
|
||||
|
||||
return True
|
||||
|
||||
for n1, n2 in edges:
|
||||
if not union(n1, n2):
|
||||
return [n1, n2]
|
||||
Reference in new issue
Block a user