算法学习(八)

算法# 学习目标:优先搜索算法(一 )

学习内容:

优先搜索算法:包括深度优先搜索和广度优先搜索;深度优先搜索(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
					
上一篇:leetcode常规算法题复盘(第十五期)——除法求值&省份数量&由斜杠划分区域&连通网络的操作次数


下一篇:算法题(八)--相同的树