算法# 学习目标:优先搜索算法(一 )
学习内容:
优先搜索算法:包括深度优先搜索和广度优先搜索;深度优先搜索(DFS):在搜索到一个新节点时,立即对该新节点进行遍历;因此遍历需要用先入后出的栈来实现,也可以通过与栈等价的递归来实现;广度优先搜索(BFS):一层层进行遍历,需要用先入先出的队列进行遍历。
学习产出:
深度优先搜索(DFS)
深度优先搜索(DFS)
主要用于树结构遍历,检测环路。
深度优先搜索一般分为主函数和辅函数,主函数用于遍历所有位置,判断是否可以开始搜索,如果可以即在辅函数进行搜索。辅函数则辅助深度优先搜索的递归调用。当然也可以使用栈,在实际中,栈的写法一是容易理解,而是不容易出现递归栈满的情况。
LeetCode 695 岛屿的最大面积
给定一个包含了一些 0 和 1 的非空二维数组 grid 。
一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为 0 。)
示例 1:
[[0,0,1,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,1,1,0,1,0,0,0,0,0,0,0,0],
[0,1,0,0,1,1,0,0,1,0,1,0,0],
[0,1,0,0,1,1,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0,1,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,0,0,0,0,0,0,1,1,0,0,0,0]]
对于上面这个给定矩阵应返回 6。注意答案不应该是 11 ,因为岛屿只能包含水平或垂直的四个方向的 1 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/max-area-of-island
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
对一块土地,以 4个方向探索与之相连的每一个土地(以及与这些土地相连的土地),那么探索过的土地总数将是该连通形状的面积。同时为了确保每个土地访问不超过一次,我们每次经过一块土地时,将这块土地的值置为 0。这样我们就不会多次访问同一土地。
步骤:
1.设计主函数,用于遍历所有位置
2.辅函数,用于探索4个方向和将访问过的土地置为0
代码(python)递归写法
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int: #主函数遍历所有位置
n,m = len(grid), len(grid[0]) #行数和列数
def DFS(grid, i, j): #辅函数探索四个方向并将其置为0
if 0 <= i < n and 0 <= j < m and grid[i][j]: #判断是否存在陆地
grid[i][j] = 0 #将访问过的土地置为0
return 1 + DFS(grid, i-1, j) + DFS(grid, i+1, j) + DFS(grid, i, j-1) + DFS(grid, i, j+1)#遍历该土地的4个方向
return 0
result = 0
# 遍历所有位置
for x in range(m):
for y in range(n):
result = max(result,dfs(grid,x,y))#保留最大值
return result
代码(python)栈写法
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
result = 0
#将岛屿信息写入栈
for i, l in enumerate(grid):
for j, n in enumerate(l):
cur = 0
stack = [(i, j)] #入栈
while stack:
cur_i, cur_j = stack.pop() #出栈
if cur_i < 0 or cur_j < 0 or cur_i == len(grid) or cur_j == len(grid[0]) or grid[cur_i][cur_j] != 1: #判断是否为越界或不存在岛屿
continue
cur += 1 #岛屿面积统计
grid[cur_i][cur_j] = 0 #将访问过的土地置为0
for di, dj in [[0, 1], [0, -1], [1, 0], [-1, 0]]: #用list[[0, 1], [0, -1], [1, 0], [-1, 0]]表示岛屿的四个方向
next_i, next_j = cur_i + di, cur_j + dj #岛屿4个方向
stack.append((next_i, next_j)) #岛屿4个方向入栈
result = max(ans, cur) #保留最大值
return result
LeetCode 547 省份数量
有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。
示例 1:
输入:isConnected = [[1,1,0],[1,1,0],[0,0,1]]
输出:2
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-provinces
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
本题拥有n个节点,每个节点最多有n条边,表示和所有城市为省份;至少有1条边,表示自己为省份。该题即为搜索省份的个数
代码(python)
class Solution:
def findCircleNum(self, isConnected: List[List[int]]) -> int: #主函数
n, visited, count = len(isConnected), [False] * len(isConnected), 0 #定义矩阵长度,辅助矩阵表示标志,省份统计
def DFS(isConnected, i, visited): #辅助函数
visited[i] = True
for j in range(n):
if isConnected[i][j] and not visited[j] : #搜索一个省份的所有城市
DFS(isConnected, j, visited)
for i in range(n): #遍历所有位置
if not visited[i]:
DFS(isConnected, i, visited)
count += 1
return count
LeetCode 417 太平洋大西洋水流问题
给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度。“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界。
规定水流只能按照上、下、左、右四个方向流动,且只能从高到低或者在同等高度上流动。
请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标。
提示:
1.输出坐标的顺序不重要
2.m 和 n 都小于150
示例:
给定下面的 5x5 矩阵:
太平洋 ~ ~ ~ ~ ~
~ 1 2 2 3 (5) *
~ 3 2 3 (4) (4) *
~ 2 4 (5) 3 1 *
~ (6) (7) 1 4 5 *
~ (5) 1 1 2 4 *
* * * * * 大西洋
返回:
[[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (上图中带括号的单元).
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/pacific-atlantic-water-flow
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
本题要求满足向下流能到达两个大洋的位置,如果我们对所有位置进行搜索,那么在不剪枝的情况下复杂度很高,因此采取逆向思维,从两大洋开始向上流,这样只需对矩形四边经行搜索,且只需遍历一次举证,满足条件(两大洋向上流都能到达的位置)
代码(python)
class Solution:
def pacificAtlantic(self, matrix: List[List[int]]) -> List[List[int]]: #主函数
def dfs(stack, flood, mark): #辅函数
while stack:
ci, cj = stack.pop() #出栈
for di, dj in [(-1, 0), (1, 0), (0, -1), (0, 1)]: #位置的4个方向
ti, tj = ci + di, cj + dj
if (
0 <= ti < m
and 0 <= tj < n
and flood[ti][tj] != mark
and matrix[ti][tj] >= matrix[ci][cj]
): #判断边界和水是否能流
flood[ti][tj] = mark
stack.append((ti, tj)) #入栈
ans = []
if not matrix:
return ans
m, n = len(matrix), len(matrix[0])
floodP = [["_"] * n for _ in range(m)] #太平洋
floodA = [["*"] * n for _ in range(m)] #大西洋
P = []
A = []
for i in range(m):
for j in range(n):
if i == 0 or j == 0:
P.append((i, j))
floodP[i][j] = "P"
if i == m - 1 or j == n - 1:
A.append((i, j))
floodA[i][j] = "A"
dfs(P, floodP, "P")
dfs(A, floodA, "A")
for i in range(m):
for j in range(n):
if floodP[i][j] == "P" and floodA[i][j] == "A":
ans.append((i, j))
return ans