回溯算法框架:
result = []
def backtrack(路径, 选择列表):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择
backtrack(路径, 选择列表)
撤销选择
多叉树的遍历框架
def traverse(TreeNode root):
for child in root.children:
#前向遍历需要的操作
traverse(dhild)
#后向遍历需要的操作
全排列问题
def permutation(nums):
def backtrack(nums, tmp):
# 如果tmp中满了,则排列完成,将临时数组加入到res中
if len(tmp) == len(nums):
res.append(tmp[:])
return
for i in range(len(nums)):
# 选择一个数加入到tmp中,如果tmp中已存在,则继续
if nums[i] in tmp:
continue
tmp.append(nums[i])
# 递归选择
backtrack(nums, tmp)
# 将最后一个数删除
tmp.pop()
res = []
backtrack(nums, [])
return res
res = permutation([1, 2, 3])
print(res)
结果:
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
子集问题
def subset(nums):
def trackback(nums, k, tmp):
res.append(tmp[:])
for i in range(k, len(nums)):
tmp.append(nums[i])
trackback(nums, i+1, tmp)
tmp.pop()
res = []
trackback(nums, 0, [])
return res
res = subset([1, 2, 3])
print(res)
结果:
[[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]]
八皇后
from pprint import pprint
class NQueue:
def __init__(self, n):
self.board = [['.' for _ in range(n)] for _ in range(n)]
self.count = 0
self.trackback(self.board, 0)
def trackback(self, board, row):
# 从第0行开始放置
if row == len(board):
print(board)
self.count += 1
return
n = len(board)
for col in range(n):
if not self.isValid(board, row, col):
continue
board[row][col] = 'Q'
self.trackback(board, row + 1)
board[row][col] = '.'
# 是否可以在board[row][col]放置皇后
def isValid(self, board ,row, col):
n = len(board)
# 如果第rol列上存在Q,返回False
for i in range(n):
if board[i][col] == 'Q':
return False
# 检查右上方是否冲突
i,j = row-1, col+1
while i >=0 and j < n:
if board[i][j] == 'Q':
return False
i -= 1
j += 1
# 检查左上方是否冲突
i,j = row-1, col-1
while i >= 0 and j >= 0:
if board[i][j] == 'Q':
return False
i -= 1
j -= 1
return True
nQueen = NQueue(8)
pprint(nQueen.count)
结果:
92
组合
输入两个数字 n, k,算法输出 [1..n] 中 k 个数字的所有组合
比如输入 n = 4, k = 2,输出如下结果,顺序无所谓,但是不能包含重复(按照组合的定义,[1,2] 和 [2,1] 也算重复):
[
[1,2],
[1,3],
[1,4],
[2,3],
[2,4],
[3,4]
]
k 限制了树的高度,n 限制了树的宽度
def combine(n, k):
nums = [i for i in range(1, n+1)]
def trackback(nums, t, k, tmp):
if len(tmp) == k:
res.append(tmp[:])
return
for i in range(t, len(nums)):
tmp.append(nums[i])
trackback(nums, i+1, k, tmp)
tmp.pop()
res = []
trackback(nums, 0, k, [])
return res
res = combine(4, 2)
print(res)
结果:
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
解数独
from pprint import pprint
board = [[0 for _ in range(9)] for _ in range(9)]
def solveSudoku():
global board
# 从棋盘上的0,0位置开始
trackback(board, 0, 0)
def trackback(board, row, col):
m, n = 9, 9
# 穷举到某行的最后一列,再从下一行开始
if col == n:
return trackback(board, row+1, 0)
# 如果穷举到最后一行了, 打印棋盘,并返回True
if row == m:
pprint(board)
return True
# 每次从(row,col)位置开始,穷举到(m,n)位置
for i in range(row, m):
for j in range(col, n):
# 如果当前位置是预设了值的,就跳过,继续下一列
if board[i][j] != 0:
return trackback(board, i, j+1)
# 判断穷举出来的值是否符合规则
for k in range(1,10):
# 如果不是有效的,则继续
if not isValid(board, i, j, k):
continue
# 否则当前位置变为k
board[i][j] = k
# 如果下一列穷举返回True,返回True
if trackback(board, i, j+1):
return True
# 将i,j出还原为0,继续穷举
board[i][j] = 0
return False
return False
def isValid(board, i, j, k):
# 判断该值所在行列是否有重复
for m in range(9):
if board[i][m] == k:
return False
if board[m][j] == k:
return False
# 3×3小格中是否有重复
if board[(i//3)*3+m//3][(j//3)*3+m%3] == k:
return False
return True
solveSudoku()
结果:
[[1, 2, 3, 4, 5, 6, 7, 8, 9],
[4, 5, 6, 7, 8, 9, 1, 2, 3],
[7, 8, 9, 1, 2, 3, 4, 5, 6],
[2, 1, 4, 3, 6, 5, 8, 9, 7],
[3, 6, 5, 8, 9, 7, 2, 1, 4],
[8, 9, 7, 2, 1, 4, 3, 6, 5],
[5, 3, 1, 6, 4, 2, 9, 7, 8],
[6, 4, 2, 9, 7, 8, 5, 3, 1],
[9, 7, 8, 5, 3, 1, 6, 4, 2]]
leetcode 22. 括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
输入:n = 1
输出:["()"]
from pprint import pprint
def generateParenthesis(n):
res = []
trackback(n, n, [], res)
return res
# left,right用于左括号和右括号的个数
def trackback(left, right, tmp, res):
if right < left:
return
if left < 0 or right < 0:
return
if left == 0 and right == 0:
res.append(tmp[:])
return
tmp.append('(')
trackback(left-1, right, tmp, res)
tmp.pop()
tmp.append(')')
trackback(left, right-1, tmp, res)
tmp.pop()
res = generateParenthesis(3)
pprint(res)from pprint import pprint
def generateParenthesis(n):
res = []
trackback(n, n, [], res)
return res
# left,right用于左括号和右括号的个数
def trackback(left, right, tmp, res):
if right < left:
return
if left < 0 or right < 0:
return
if left == 0 and right == 0:
res.append(tmp[:])
return
tmp.append('(')
trackback(left-1, right, tmp, res)
tmp.pop()
tmp.append(')')
trackback(left, right-1, tmp, res)
tmp.pop()
res = generateParenthesis(3)
pprint(res)
寻找二维字母矩阵中是否存在某单词
# -*- coding:utf-8 -*-
class Solution:
def hasPath(self, matrix, path):
# write code here
def helper(matrix,path,i,j):
if len(path) == 0:
return True
haspath = False
if 0<= i < len(matrix) and 0<= j< len(matrix[0]):
if path[0] == matrix[i][j]:
matrix[i][j] = 0
haspath = helper(matrix,path[1:],i+1,j) or
helper(matrix, path[1:], i, j+1) or
helper(matrix, path[1:], i-1, j) or
helper(matrix, path[1:], i, j-1)
matrix[i][j] = path[0]
return haspath
m,n = len(matrix),len(matrix[0])
for i in range(m):
for j in range(n):
if helper(matrix,path,i,j):
return True
return False
s = Solution()
matrix = [
['h','a','l','m','n'],
['c','a','m','q','y'],
['w','e','d','e','q'],
['z','e','t','o','i'],
]
path = 'almdeoi'
print(s.hasPath(matrix,path=path))