回溯算法
回溯算法具体原理可以参考【LeetCode】46 and 112(回溯算法)。今天就来聊三道考察频率高,而且容易让人搞混的算法问题,分别是求子集(subset),求排列(permutation),求组合(combination)。这几个问题都可以用回溯算法解决。
78. 子集
解法:回溯
求解过程可以等价为对该树的回溯前序遍历。
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
result = []
# path 记录走过的路
def backtrack(start, path):
result.append(path.copy())
# 注意 i 从 start 开始递增
for i in range(start, len(nums)):
# 做选择
path.append(nums[i])
# 回溯
backtrack(i+1, path)
# 撤销选择
path.pop()
backtrack(0, [])
return result
77. 组合
解法:DFS(回溯算法)
求解过程可以等价为对该树的回溯前序遍历,取叶子节点作为结果。
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
result = []
def backtrack(start, path):
# 到达树的底部
if len(path) == k:
result.append(path.copy())
return
# 注意 i 从 start 开始递增
for i in range(start, n+1):
# 做选择
path.append(i)
# 回溯
backtrack(i+1, path)
# 撤销选择
path.pop()
backtrack(1, [])
return result
排列可以参考全排列求解
总结
可以通过对上述3道题对比分析,来更加深入的体会回溯思想的应用以及问题转化。