• 【力扣hot100】刷题笔记Day15


    前言

    • 今天要刷的是图论,还没学过,先看看《代码随想录》这部分的基础

    深搜DFS理论基础

    • 深搜三部曲

      • 确认递归函数、参数
      • 确认终止条件
      • 处理目前搜索节点出发的路径
    • 代码框架

        1. void dfs(参数) {
        2. if (终止条件) {
        3. 存放结果;
        4. return;
        5. }
        6. for (选择:本节点所连接的其他节点) {
        7. 处理节点;
        8. dfs(图,选择的节点); // 递归
        9. 回溯,撤销处理结果
        10. }
        11. }

    797. 所有可能的路径 - 力扣(LeetCode)

    • DFS

        1. class Solution:
        2. def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]:
        3. res = [] # 存放结果
        4. path = [0] # 当前路径
        5. def dfs(root: int):
        6. if root == len(graph) - 1: # 如果到达最后节点存入结果,
        7. res.append(path[:]) # path[:]避免使用引用,deep copy
        8. return
        9. for node in graph[root]: # 遍历root所有节点
        10. path.append(node) # path加上当前遍历节点
        11. dfs(node) # 下一层继续搜索
        12. path.pop() # 回溯,撤销节点
        13. dfs(0)
        14. return res

    广搜BFS理论基础

    • 适用于解决两个点之间的最短路径问题
      1. from collections import deque
      2. dir = [(0, 1), (1, 0), (-1, 0), (0, -1)] # 创建方向元素
      3. def bfs(grid, visited, x, y):
      4. queue = deque() # 初始化队列
      5. queue.append((x, y)) # 放入第一个元素/起点
      6. visited[x][y] = True # 标记为访问过的节点
      7. while queue: # 遍历队列里的元素
      8. curx, cury = queue.popleft() # 取出第一个元素
      9. for dx, dy in dir: # 遍历四个方向
      10. nextx, nexty = curx + dx, cury + dy
      11. if nextx < 0 or nextx >= len(grid) or nexty < 0 or nexty >= len(grid[0]):
      12. continue # 越界了,直接跳过
      13. if not visited[nextx][nexty]: # 如果节点没被访问过
      14. queue.append((nextx, nexty)) # 加入队列
      15. visited[nextx][nexty] = True # 标记为访问过的节点

     200. 岛屿数量 - 力扣(LeetCode)

    • DFS

        1. class Solution:
        2. def numIslands(self, grid: List[List[str]]) -> int:
        3. m, n = len(grid), len(grid[0])
        4. # visited = [[False] * n for _ in range(m)] # 如果不能修改用标记grid
        5. # 深搜当前陆地部分
        6. def dfs(x, y): # x表示行,y表示列
        7. grid[x][y] = "0" # 遍历到的节点就置为0以防重复,用visited则删除此句
        8. for nx, ny in [(x-1,y), (x+1,y), (x,y-1), (x,y+1)]:
        9. if 0 <= nx < m and 0 <= ny < n and grid[nx][ny] == "1":
        10. # if 0 <= nx < m and 0 <= ny < n and grid[nx][ny] == "1" and not visited[nx][ny]:
        11. # visited[nx][ny] = True
        12. dfs(nx,ny)
        13. # 依次遍历每个节点搜索大陆
        14. res = 0
        15. for i in range(m):
        16. for j in range(n):
        17. if grid[i][j] == "1":
        18. # if not visited[i][j] and grid[i][j] == '1':
        19. # visited[i][j] = True
        20. res += 1 # 遇到没访问过的陆地,+1
        21. dfs(i, j)
        22. # 返回总陆地数
        23. return res
    •  BFS

        1. class Solution:
        2. def numIslands(self, grid: List[List[str]]) -> int:
        3. m, n = len(grid), len(grid[0])
        4. # visited = [[False] * n for _ in range(m)] # 如果不能修改用visited标记grid中已访问节点
        5. # 广搜当前陆地部分
        6. def bfs(x, y): # x表示行,y表示列
        7. q = deque()
        8. q.append((x,y))
        9. grid[x][y] = "0" # 遍历到的节点就置为0以防重复,用visited则删除此句
        10. # visited[x][y] = True # 用visited
        11. while q:
        12. x0, y0 = q.popleft() # 当前遍历节点加入队列
        13. for nx, ny in [(x0-1,y0), (x0+1,y0), (x0,y0-1), (x0,y0+1)]:
        14. if 0 <= nx < m and 0 <= ny < n and grid[nx][ny] == "1": # 用visited则删除此句
        15. # if 0 <= nx < m and 0 <= ny < n and grid[nx][ny] == "1" and not visited[nx][ny]:
        16. q.append((nx, ny))
        17. grid[nx][ny] = "0" # 加入列表就标记为访问过,用visited则删除此句
        18. # visited[nx][ny] = True # 用visited
        19. # 依次遍历每个节点搜索大陆
        20. res = 0
        21. for i in range(m):
        22. for j in range(n):
        23. if grid[i][j] == "1":
        24. # if not visited[i][j] and grid[i][j] == '1':
        25. res += 1 # 遇到没访问过的陆地,+1
        26. bfs(i, j)
        27. # 返回总陆地数
        28. return res
    • 并查集 

      • 没接触过并查集,依据这道题在B站大学找了相关视频文章学习一下
        1. ## 解法三:UnionFind 并查集经典解法
        2. class UnionFind: ## 定义为一个类。后面类似的题目,也可以直接搬去使用
        3. def __init__(self, grid): ## 初始化
        4. m, n = len(grid), len(grid[0])
        5. self.count = 0 ## count 是最终结果,初始化为0
        6. self.parent = [-1] * (m * n) ## 初始化 parent 数组取值全部为 -1
        7. ## rank 秩,表示树的高度,在连接的时候要规定秩小的指向秩大的元素
        8. self.rank = [0] * (m * n) ## rank 用来实现上下左右的合并;初始化全部为 0
        9. ## 计算陆地的总数 count;修改 parent 数组陆地元素的取值
        10. for i in range(m):
        11. for j in range(n):
        12. if grid[i][j] == "1": ## 对于陆地元素,把它的parent初始化为它的一维化的位置
        13. self.parent[i * n + j] = i * n + j ## parent初始化为元素本身的一维化的(位置)索引
        14. self.count += 1 ## 陆地总数
        15. ## find 方法给union 方法调用
        16. def find(self, i):
        17. if self.parent[i] != i: ## 对于索引不等于自身的元素
        18. self.parent[i] = self.find(self.parent[i]) ## 路径优化。把所有链式关系,简化为一层的父子关系
        19. return self.parent[i] ## 返回父亲的索引(也等于该索引对应的取值)
        20. ## 最关键是 union 方法,用来处理目标元素并计算岛屿数量
        21. def union(self, x, y):
        22. rootx = self.find(x) ## 找到自己的 root 索引
        23. rooty = self.find(y) ## 找到自己的 root 索引
        24. if rootx != rooty: ## 如果不等,则进行合并
        25. if self.rank[rootx] <= self.rank[rooty]: ## 如果 rank 更小
        26. self.parent[rootx] = rooty ## 秩小的指向秩大的元素
        27. else:
        28. self.parent[rooty] = rootx ## 秩小的指向秩大的元素
        29. if self.rank[rootx] == self.rank[rooty]: ## 如果秩相等
        30. self.rank[rootx] += 1 ## 如果深度相同,新节点的 rank + 1
        31. self.count -= 1 ## 合并一次,则陆地数量减一(岛屿数量=陆地数量-总的合并次数)
        32. ## 主类 + 主函数
        33. class Solution:
        34. def numIslands(self, grid: List[List[str]]) -> int: ## 主函数
        35. nr = len(grid) ## number of row
        36. if nr == 0:
        37. return 0
        38. nc = len(grid[0]) ## number of column
        39. uf = UnionFind(grid) ## 调用并查集函数
        40. ## 遍历每一个位置
        41. for r in range(nr):
        42. for c in range(nc):
        43. if grid[r][c] == "1": ## 碰到陆地 1
        44. grid[r][c] = "0" ## 先修改为 0
        45. for x, y in [(r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)]: ## 遍历上下左右
        46. if 0 <= x < nr and 0 <= y < nc and grid[x][y] == "1": ## 碰到新的 1
        47. uf.union(r * nc + c, x * nc + y) ## 调用并查集函数
        48. return uf.count

    后言

    • 并查集这个学得我好累,这就是缺乏基础吧,路漫漫啊 
  • 相关阅读:
    Elasticsearch面试题(查漏补缺)
    Python之魔幻切片——万物可切(只要是序列对象)。负整数步长一出,序列瞬间倒置,可以玩儿更多花样。
    基于 CNN-GRU 的菇房多点温湿度预测方法研究 学习记录
    1.安装环境
    一个项目应对各式各样环境-profile完美应付
    消防大数据分析
    SpringMVC学习篇(十)
    【图解源码】Zookeeper3.7源码分析,包含服务启动流程源码、网络通信源码、RequestProcessor处理请求源码
    网络安全系列-三十四: EDR、NDR、XDR 、HIPS、NIPS、NTA、DPI、DFI、南北流量、东西流量:傻傻分不清楚
    MySQL基础知识整理
  • 原文地址:https://blog.csdn.net/qq_56077562/article/details/136316323