Problems that can be solved by the backtracking algorithm: combination problems , cutting problems, subset problems , permutation problems , chessboard problems .
The backtracking algorithm is to perform a depth-first traversal on the tree or graph structure . In fact, it is similar to the enumeration search attempt process, and finds the solution to the problem during the traversal process.
Depth-first traversal has a feature: when it is found that the solution condition is not met, it returns and tries another path. At this time, the object type variable needs to be reset to be the same as before, which is called "state reset".
Many complex and large-scale problems can use the backtracking method, which has the reputation of "universal problem-solving method". In fact, the backtracking algorithm is a violent search algorithm. It is an algorithm used in early artificial intelligence. It helps us find solutions to problems with the help of powerful computing power of computers.
combination problem
给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。
candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是唯一的。
class Solution(object):
def combinationSum(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
nums = sorted(candidates)
res = []
def recursive(idx, targ, cur):
for i in range(idx, len(nums)):
ni = nums[i]
if ni < targ:
recursive(i, targ-ni, cur+[ni])
else:
if ni == targ:
res.append(cur+[ni])
break
recursive(0, target, [])
return res
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
注意:解集不能包含重复的组合。
class Solution(object):
def combinationSum2(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
nums = sorted(candidates)
res = []
def recursive(idx, targ, cur):
for i in range(idx, len(candidates)):
ni = nums[i]
if ni < targ:
if i == idx or ni != nums[i-1]:
recursive(i+1, targ-ni, cur+[ni])
else:
if ni == targ:
res.append(cur+[ni])
break
recursive(0, target, [])
return res
216. Combined Sum III LeetCode-python 216. Combined Sum III - Short Book
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
说明:所有数字都是正整数。
解集不能包含重复的组合。
class Solution(object):
def combinationSum3(self, k, n):
"""
:type k: int
:type n: int
:rtype: List[List[int]]
"""
res = []
def recursive(k, n, index, path):
if k == 0 or n < 0:
if n == 0:
res.append(path)
return
for i in range(index, 10):
recursive(k-1, n-i, i+1, path+[i])
recursive(k, n, 1, [])
return res
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
class Solution(object):
def combine(self, n, k):
"""
:type n: int
:type k: int
:rtype: List[List[int]]
"""
def recursive(start, end, k, cur, result):
if len(cur) == k:
result.append(cur)
return None
for i in range(start,end+1):
recursive(i+1,end,k,cur+[i],result)
return None
if k > n:
return []
res = []
recursive(1,n,k,[],res)
return res
permutation problem
给定一个不含重复数字的数组nums ,返回其所有可能的全排列 。你可以按任意顺序返回答案。
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
res = []
path = []
def backtrack(nums, path):
if len(path) == len(nums):
res.append(path)
for i in range(len(nums)):
if nums[i] in path:
continue
backtrack(nums, path+[nums[i]])
backtrack(nums, [])
return res
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
class Solution(object):
def permuteUnique(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums.sort()
res = []
def dfs(nums, path):
if not nums:
res.append(path)
return
for i in range(len(nums)):
if i>0 and nums[i]==nums[i-1]:
continue
dfs(nums[:i]+nums[i+1:], path+[nums[i]])
dfs(nums, [])
return res
subset problem
78. Subset
LeetCode 78 Subset python_孤行-CSDN Blog
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
class Solution(object):
def subsets(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
res = [[]]
for i in range(len(nums)-1, -1, -1):
for subres in res[:]: #切片的作用是使得res不变
res.append(subres+[nums[i]])
return res
方法二:创建一个内函数 通过遍历start到nums的长度 遍历递归调用函数 然后加入到res中
class Solution(object):
def subsets(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
res = []
def temp(start, num):
res.append(num)
for i in range(start, len(nums)):
temp(i+1, num+[nums[i]])
temp(0, [])
return res
class Solution(object):
def subsetsWithDup(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums.sort() # sort the nums to find the equivalent nums
res = []
def temp(start, num):
res.append(num)
for i in range(start, len(nums)):
if i>start and nums[i] == nums[i-1]:
continue # pass the same number
else:
temp(i+1, num+[nums[i]])
temp(0, [])
return res
Sword refers to Offer 38. Arrangement of strings
Similar to the idea of frog jumping steps , no matter how long the given string is, the combined pattern it arranges can be decomposed into the pattern of "the first character + the remaining characters". Different characters in the first digit can be respectively assigned by traversing, and the "remaining characters" can be decomposed as above.
(This solution is extremely slow and needs to be optimized)
class Solution(object):
def permutation(self, s):
"""
:type s: str
:rtype: List[str]
"""
l = []
if len(s) <= 1:
return [s]
n = len(s)
for i in range(n):
for j in self.permutation(s[:i]+s[i+1:]):
temp = s[i] + str(j)
if temp not in l:
l.append(temp)
return l
784. Full Arrangement of Letters and Cases
17. Alphabet combinations for phone numbers
class Solution(object):
def letterCombinations(self, digits):
"""
:type digits: str
:rtype: List[str]
"""
# 创建字母对应的字符列表的字典
dic = {2: ['a', 'b', 'c'],
3: ['d', 'e', 'f'],
4: ['g', 'h', 'i'],
5: ['j', 'k', 'l'],
6: ['m', 'n', 'o'],
7: ['p', 'q', 'r', 's'],
8: ['t', 'u', 'v'],
9: ['w', 'x', 'y', 'z'],
}
# 存储结果的数组
res = []
if len(digits) == 0:
return []
# 递归出口,当递归到最后一个数的时候result拿到结果进行for循环遍历
if len(digits) == 1:
return dic[int(digits[0])]
# 递归调用
result = self.letterCombinations(digits[1:])
# result是一个数组列表,遍历后字符串操作,加入列表
for r in result:
for j in dic[int(digits[0])]:
res.append(j + r)
return res
22. Bracket generation (backtracking method (actually also a kind of DFS))
class Solution(object):
def generateParenthesis(self, n):
"""
:type n: int
:rtype: List[str]
"""
res = []
def backtrack(prefix, left, right):
if len(prefix) == 2 * n:
res.append(prefix)
return
# 控制左括号的数量,避免出现'(((((('的情况
if left < n:
backtrack(prefix + '(', left + 1, right)
# 控制右括号的数量
if right < left:
backtrack(prefix + ')', left, right + 1)
backtrack('', 0, 0)
return res
79. Word search (depth-first search, searched places should be marked to avoid repeated searches)
class Solution(object):
def exist(self, board, word):
"""
:type board: List[List[str]]
:type word: str
:rtype: bool
"""
n, m = len(board), len(board[0])
def dfs(board, x, y, word):
if not word:
return True
if 0<=x<n and 0<=y<m and board[x][y] == word[0] and board[x][y]!='#':
t, board[x][y] = board[x][y], '#'
res = dfs(board, x, y+1, word[1:]) or dfs(board, x, y-1, word[1:]) or dfs(board, x+1, y, word[1:]) or dfs(board, x-1, y, word[1:])
board[x][y] = t
return res
return False
for i in range(n):
for j in range(m):
if dfs(board,i,j,word):
return True
return False
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def pathSum(self, root, targetSum):
"""
:type root: TreeNode
:type targetSum: int
:rtype: List[List[int]]
"""
res = []
def dfs(target, root, path):
if not root.left and not root.right:
if target == root.val:
res.append(path+[root.val])
if root.left:
dfs(target-root.val, root.left, path+[root.val])
if root.right:
dfs(target-root.val, root.right, path+[root.val])
if not root:
return []
dfs(targetSum, root, [])
return res
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。
class Solution:
def partition(self, s: str) -> List[List[str]]:
length = len(s)
res = []
def dfs(start, tmp):
if start >= length:
res.append(tmp)
for i in range(start, length):
substring = s[start:i + 1]
if substring == substring[::-1]: #子串是回文串
dfs(i + 1, tmp+[substring])
dfs(0, [])
return res