mirror of
https://github.com/prdlk/leetcode.git
synced 2026-11-02 21:22:43 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0f479d6cf |
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 });
|
||||||
@@ -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
|
||||||
Reference in new issue
Block a user