【python刷题】回溯算法(深度优先搜索DFS)

回溯算法框架:

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))
原文地址:https://www.cnblogs.com/xiximayou/p/14361950.html