先举个栗子
一颗二叉树如下,搜索所有路径
DFS的做法是:
每条路走到头(叶节点),然后再回头寻找其他路。上图为例,1出发到2,到4,到8,走到头了,退回4,退回2,到5,退回2,退回1,到3,到6,…,知道走完到7。
BFS的做法是:
自上而下,一层一层的走。上图为例,1出发,可以到2和3两个位置,存储起来[2,3],2可以到4和5,3可以到6和7,存储为[4,5,6,7],继续走,存储[8,9,10],继续走,存储[11],就走完了所有的路径。
下面是两种方法的思想以及各自的应用场景。
DFS(深度优先搜索)
- 思想:
运用递归回溯的思想,保存当前搜索路径,深入搜索,直到该路径最深位置,然后回溯到上一个节点,继续搜索其他路径,若无则继续回溯,直到把所有路径最深位置都搜索一遍。 - 注意:
搜索过程记录的路径,在回溯时需要抛弃路径的最后一个节点。还是以上图为例,加入当前路径为[1,2,4,8],当回溯到4时,应把8抛弃,路径变为[1,2,4],继续回溯[1,2],然后搜索5,[1,2,5]。 - 使用:
def dfs(node,path):
if (node.left == None and node.right == None): #当搜索到叶子结点时返回,也可以是满足某种条件时
# 一些操作,比如把当前路径记录在结果中
return
if #满足某种条件且有路可走:
path.append(node) #将当前节点加入路径
if node.left:
dfs(node.left)
if node.right:
dfs(node.right)
path.pop #回溯前删除当前节点
BFS(广度优先搜索)
- 思想:
使用列表保存每一层可搜索节点。具体执行过程是,遍历上一层保存列表中的每一个节点,并保存该节点可搜索的下一层节点。一层一层直到结束或满足某种条件。 - 注意:
BFS的变体有很多,需要根据具体的场景和题目,设计相应的实现。 - 使用:
def bfs(root): #也可加入path记录路径,具体问题具体分析
pre = [] #保存上一层可搜索点
cur = [] #保存当前层可搜索点
pre.append(root)
while cur:#也可以是其他的条件,这里仅以逐层搜索为例
for node in cur:
if node.left:
cur.append(node.left)
if node.right:
cur.append(node.right)
pre = cur
cur = []
DFS和BFS应用场景及例题:
- DFS适合搜索全部的解,以时间换空间;
- BFS适合搜索最短路径,以空间换时间;
例1(DFS):
(剑指offer)输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回二维列表,内部每个列表表示找到的路径
def FindPath(self, root, expectNumber):
# write code here
if not root:
return []
res = []
self.findit(root, 0, expectNumber, [], res)
return res
def findit(self, node, csum, enum, path, res):
csum += node.val
path.append(node)
if csum == enum:
if not node.left and not node.right:
onepath = [i.val for i in path]
res.append(onepath)
if csum < enum:
if node.left:
self.findit(node.left, csum, enum, path, res)
if node.right:
self.findit(node.right, csum, enum, path, res)
path.pop()
DFS例2(DFS&BFS):
(Leetcode 200) 岛屿的个数:给定一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,计算岛屿的数量。岛屿被水包围,通过水平或垂直连接相邻的陆地形成。你可以假设网格的四边都被水包围着。
示例1:
输入:
11110
11010
11000
00000
输出:1
示例 2:
输入:
11000
11000
00100
00011
输出:3
- DFS代码:
class Solution:
def numIslands(self, grid):
if len(grid) == 0:
return 0
m = len(grid)
n = len(grid[0])
count = 0
cur = []
for i in range(m):
for j in range(n):
if grid[i][j] == '1':
count += 1
self.dfs(i, j, m, n, grid)
return count
def dfs(self, x, y, m, n, grid):
grid[x][y] = '0'
if x - 1 >= 0 and grid[x - 1][y] == '1':
self.dfs(x - 1, y, m, n, grid)
if x + 1 < m and grid[x + 1][y] == '1':
self.dfs(x + 1, y, m, n, grid)
if y - 1 >= 0 and grid[x][y - 1] == '1':
self.dfs(x, y - 1, m, n, grid)
if y + 1 < n and grid[x][y + 1] == '1':
self.dfs(x, y + 1, m, n, grid)
- BFS代码:
class Solution:
def numIslands(self, grid):
if len(grid) == 0:
return 0
m = len(grid)
n = len(grid[0])
count = 0
for i in range(m):
for j in range(n):
if grid[i][j] == '1':
count += 1
grid[i][j] = '0'
self.bfs([(i, j)], m, n, grid)
return count
def bfs(self, pre, m, n, grid):
while pre:
cur = []
for x, y in pre:
if x - 1 >= 0 and grid[x - 1][y] == '1':
gride[x - 1][y] = '0'
cur.append((x - 1, y))
if x + 1 < m and grid[x + 1][y] == '1':
grid[x + 1][y] = '0'
cur.append((x + 1, y))
if y - 1 >= 0 and grid[x][y - 1] == '1':
grid[x][y - 1] = '0'
cur.append((x, y - 1))
if y + 1 < n and grid[x][y + 1] == '1':
grid[x][y + 1] = '0'
cur.append((x, y + 1))
pre = cur
- 其他解法: 这个题还有一种解法,利用栈
class Solution:
def numIslands(self, grid):
if len(grid) == 0:
return 0
m = len(grid)
n = len(grid[0])
count = 0
cur = []
for i in range(m):
for j in range(n):
if grid[i][j] == '1':
count += 1
cur.append((i, j))
while cur:
x, y = cur.pop()
grid[x][y] = '0'
if x - 1 >= 0 and grid[x - 1][y] == '1':
cur.append((x - 1, y))
if x + 1 < m and grid[x + 1][y] == '1':
cur.append((x + 1, y))
if y - 1 >= 0 and grid[x][y - 1] == '1':
cur.append((x, y - 1))
if y + 1 < n and grid[x][y + 1] == '1':
cur.append((x, y + 1))
return count
先写到这里吧,这一天天的,过得好快,遇到同样算法的例题再做补充!~