中等难度-BFS

来源于leetcode题库102,200,207

BFS解题模版

#BFS模版
# (1)不需要确定当前遍历到哪一层
while queue 不空:
    cur = queue.pop()
    for 节点 in cur的所有相邻节点:
        if 该节点有效且未访问过:
            queue.push(该节点)
# (2)需要确定当前遍历到哪一层了
'''
level表示当前遍历到二叉树中的哪一层了,
也可以理解为在一个图中,现在已经走了多少步了
'''
level = 0
while queue 不空:
    size = queue.size()
    while (size --) {
        cur = queue.pop()
        for 节点 in cur的所有相邻节点:
            if 该节点有效且未被访问过:
                queue.push(该节点)
    }
    level ++;

102.二叉树的层序遍历

  • 题目描述
    • 给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
  • 示例
二叉树:[3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回其层次遍历结果:

[
  [3],
  [9,20],
  [15,7]
]


  • 题解

for i in range(10):
循环体中可以使用i
for _ in range(10):
用下划线则仅用于控制循环次数,后边不会用到该变量


class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        #创建队列并将根节点加入队列
        queue = collections.deque()
        queue.append(root)
        res = []
        #套用模板
        while queue:
            size = len(queue)
            level = []
            for _ in range(size):
                cur = queue.popleft()
                if not cur:
                    continue
                # 每一层的值
                level.append(cur.val)
                # 将该节点的左右子节点加入队列
                queue.append(cur.left)
                queue.append(cur.right)
            if level:#将值放进结果中
                res.append(level)
        return res

200.岛屿数量

  • 题目描述
    • 给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。

  • 示例


    image.png
  • 题解
    来自大佬莲子熊猫

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        count = 0
        for row in range(len(grid)):#行
            for col in range(len(grid[0])):#列
                if grid[row][col] == '1':  # 发现陆地
                    count += 1  # 结果加1
                    grid[row][col] = '0'  # 将其转为 ‘0’ 代表已经访问过
                    # 对发现的陆地进行扩张即执行 BFS,将与其相邻的陆地都标记为已访问
                    # BFS 模板
                    land_positions = collections.deque()
                    land_positions.append([row, col])
                    while len(land_positions) > 0:
                        x, y = land_positions.popleft()
                         # 进行四个方向的扩张
                        for new_x, new_y in [[x, y + 1], [x, y - 1], [x + 1, y], [x - 1, y]]: 
                            # 判断有效性
                            if 0 <= new_x < len(grid) and 0 <= new_y < len(grid[0]) and grid[new_x][new_y] == '1':
                                grid[new_x][new_y] = '0'  # 因为可由 BFS 访问到,代表同属一块岛,将其置 ‘0’ 代表已访问过
                                land_positions.append([new_x, new_y])
        return count


207.课程表

  • 题目描述:
    • 你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。
      在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]
      给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?
  • 示例:

输入: 2, [[1,0]]
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
示例 2:
输入: 2, [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。

  • 题解:
class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        '''
        有向无圈图DAG,如果构成环路是不成立的
        通过拓扑排序判断是否是DAG:
            对DAG对顶点进行排序,使得每一条有向边(u,v),均符合y比v先出现
        DFS解法
        借助一个列表flags用于判断每个节点的状态:
            未被访问,i==0
            已被其他节点启动的DFS访问,i==-1
            已被当前节点启动的DFS访问,i==1
        对numCourses个节点依次执行DFS,判断是否有环:
            当flags[i]==-1,被其他节点访问过,返回True
            当flags[i]==1,已在本轮搜索中访问过,即有环,返回False
            将当前节点i对应flags[i]置为1,表示本轮访问过
            递归访问当前节点i的所有邻接节点j,发现环返回False
            当前节点的所有邻接节点也被遍历,则当前节点置为-1,返回True
        如果整个图DFS结束都没发现环,返回True
        '''
        def dfs(i,adjacency,flags):
            #终止条件
            if flags[i] == -1:
                return True
            if flags[i] == 1:
                return False
            #当前点置为1
            flags[i] = 1
            #对当前节点对所有邻接点进行dfs
            for j in adjacency[i]:
                if not dfs(j,adjacency,flags):
                    return False
            #没有环则当前节点置为-1,下次不需要再进行dfs了,返回True
            flags[i] = -1
            return True
        #
        adjacency = [[] for _ in range(numCourses)]
        flags = [0 for _ in range(numCourses)]
        for cur,pre in prerequisites:
            adjacency[pre].append(cur)
        #对所有节点进行dfs
        for i in range(numCourses):
            if not dfs(i,adjacency,flags):
                return False
        return True

        '''
        BFS解法:
        统计课程安排图中每个节点的入度,生成入度表indegrees
        借助一个队列queue,将所有入度为0的节点入队
        当queue不为空,依次队首节点出队,在课程安排图中删除此节点pre
            并不是真正从邻接表删除,而是此节点对应所有邻接节点cur-1
            当入度-1后邻接节点cur的入度为0,说明cur的前驱节点已经被删除,此时cur入队
        在每次pre出队时,执行numCourses--
            若课程安排图是DAG,则所有节点都出队入队过
            如图中存在环,则一定有节点的入度始终不为0
            拓扑排序出队次数等于课程个数,返回numCourses==0可以判断是否成功
        '''
        
        #入度表
        indegrees = [0 for _ in range(numCourses)]
        #课程的依赖
        adjacency = [[] for _ in range(numCourses)]
        queue = collections.deque()
        # 入度表记录所有节点的入度,
        for cur,pre in prerequisites:
            indegrees[cur] += 1
            adjacency[pre].append(cur)
        #入度不为0的加入队列
        for i in range(len(indegrees)):
            if not indegrees[i]:
                queue.append(i)
        #BFS
        while queue:
            #取出队首数据
            pre = queue.popleft()
            numCourses -= 1
            #遍历队首的所有邻接元素
            for cur in adjacency[pre]:
                indegrees[cur] -= 1
                #如果邻接元素入度-1后还不为0,则将其加入队列
                if not indegrees[cur]:
                    queue.append(cur)
        return numCourses == 0
        
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容