Compare commits

...
Author SHA1 Message Date
Prad Nukala f0f479d6cf feat: add lc 46, 39, 78 2026-09-24 14:36:19 -04:00
8 changed files with 496 additions and 0 deletions

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
```
+163
View File
@@ -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.
+3
View File
@@ -0,0 +1,3 @@
import { defineMeta } from "blume";
export default defineMeta({ title: "Backtracking", order: 20 });
+75
View File
@@ -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
+59
View File
@@ -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
+50
View File
@@ -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