系列文章目录
leetcode刷题:第一周
leetcode刷题:第二周
leetcode刷题:二分查找
leetcode刷题:双指针
leetcode刷题:广度/深度优先搜索
leetcode刷题:递归 / 回溯
前言
这次博客记录一些leetcode有关递归和回溯的题目
递归/回溯
1.子集
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入:nums = [0]
输出:[[],[0]]
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
result = []
def backtrack(start, k, cur, nums):
if k == 0:
#使用[:]调用一块新内存
result.append(cur[:])
return
for i in range(start, n):
cur.append(nums[i])
backtrack(i + 1, k - 1, cur, nums)
cur.pop()
n = len(nums)
for k in range(n + 1):
backtrack(0, k, [], nums)
return result
2.子集 II
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
示例 1:
输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
示例 2:
输入:nums = [0]
输出:[[],[0]]
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
#先排序可以避免重复
nums.sort()
result = []
def backtrack(start, k, cur, nums):
if k == 0:
#加入结果列表前,判断结果是否存在
if cur not in result:
result.append(cur[:])
return
for i in range(start, n):
cur.append(nums[i])
backtrack(i + 1, k - 1, cur, nums)
cur.pop()
n = len(nums)
for k in range(n + 1):
backtrack(0, k, [], nums)
return result
3.全排列 II
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
示例 1:
输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]
示例 2:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
result = []
lens = len(nums)
used = [0] * lens
if lens == 0:
return []
depth = 0
path = []
def dfs(nums, lens, depth, used, path):
if depth == lens and path[:] not in result:
result.append(path[:])
return
for i in range(lens):
if used[i] == 1:
continue
path.append(nums[i])
used[i] = 1
dfs(nums, lens, depth + 1, used, path)
path.pop()
used[i] = 0
dfs(nums, lens, depth, used, path)
return result
4.组合总和
给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。
示例 1:
输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。
示例 2:
输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]
示例 3:
输入: candidates = [2], target = 1
输出: []
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
ans = []
combine = []
def dfs(candidates, target, idx):
if idx == len(candidates):
return
if target == 0:
ans.append(combine[:])
return
dfs(candidates, target, idx + 1)
if target - candidates[idx] >= 0:
combine.append(candidates[idx])
dfs(candidates, target - candidates[idx], idx)
combine.pop()
dfs(candidates, target, 0)
return ans
5.组合总和 II
给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
path = []
def backtrack(candidates, target, sum, begin):
if sum == target:
res.append(path[:])
for i in range(begin, len(candidates)):
if i > begin and candidates[i] == candidates[i - 1]:
continue
rs = candidates[i] + sum
if rs <= target:
path.append(candidates[i])
backtrack(candidates, target, rs, i + 1)
path.pop()
else:
break
candidates.sort()
backtrack(candidates, target, 0, 0)
return res
6.电话号码的字母组合
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例 1:
输入:digits = “23”
输出:[“ad”,“ae”,“af”,“bd”,“be”,“bf”,“cd”,“ce”,“cf”]
示例 2:
输入:digits = “”
输出:[]
示例 3:
输入:digits = “2”
输出:[“a”,“b”,“c”]
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
if not digits:
return []
Map = {
"2": "abc",
"3": "def",
"4": "ghi",
"5": "jkl",
"6": "mno",
"7": "pqrs",
"8": "tuv",
"9": "wxyz"
}
def backtrack(index):
if index == len(digits):
combinations.append("".join(combination))
else:
digit = digits[index]
for letter in Map[digit]:
combination.append(letter)
backtrack(index + 1)
combination.pop()
combination = []
combinations = []
backtrack(0)
return combinations
7.括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
示例 2:
输入:n = 1
输出:["()"]
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
result = []
if n <= 0:
return []
def getParenthesis(path, left, right):
if left == 0 and right == 0:
result.append(path[:])
return result
if left == right:
getParenthesis(path + "(", left - 1, right)
elif left < right:
if left > 0:
getParenthesis(path + "(", left - 1, right)
getParenthesis(path + ")", left, right - 1)
getParenthesis("", n, n)
return result
8.单词搜索
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例 1:
输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
输出:true
示例 2:
输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “SEE”
输出:true
示例 3:
输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCB”
输出:false
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
def check(i, j, k):
if board[i][j] != word[k]:
return False
if k == len(word) - 1:
return True
visited.add((i, j))
result = False
for di, dj in directions:
newi, nwej = i + di, j + dj
if 0 <= newi < h and 0 <= nwej < w:
if (newi, nwej) not in visited:
if check(newi, nwej, k + 1):
result = True
break
visited.remove((i, j))
return result
h = len(board)
w = len(board[0])
visited = set()
for i in range(h):
for j in range(w):
if check(i, j, 0):
return True
return False
总结
随着学校课程的开展,压力还是比较大的,平时没注意,最近观察发现,学校的课程量是上个学期的数倍多,上个学期只开了三门专业课,这个学期足足开了九门专业课,这段时间的leetcode入门明显,效率下降了很多。