第四章 breadth first search

宽度优先搜索:

https://blog.csdn.net/merry1996/article/details/90141800

拓扑排序:

在图论中,拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列。且该序列必须满足下面两个条件:

每个顶点出现且只出现一次。
若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面。

有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说。

在这里插入图片描述
https://www.jianshu.com/p/b59db381561a

https://blog.csdn.net/littlethunder/article/details/24113193
69. 二叉树的层次遍历
中文English
给出一棵二叉树,返回其节点值的层次遍历(逐层从左往右访问)

Example
样例 1:

输入:{1,2,3}
输出:[[1],[2,3]]
解释:

   1
  / \
 2   3

它将被序列化为{1,2,3}
层次遍历
样例 2:

输入:{1,#,2,3}
输出:[[1],[2],[3]]
解释:

1
 \
  2
 /
3

它将被序列化为{1,#,2,3}
层次遍历
Challenge
挑战1:只使用一个队列去实现它

挑战2:用BFS算法来做

Notice
首个数据为根节点,后面接着是其左儿子和右儿子节点值,"#"表示不存在该子节点。
节点数量不超过20。

#宽度优先搜索
#双端队列
from collections import deque

class Node:
    def __init__(self,val):
        self.val = val
        self.left = None
        self.right =None
        self.next = None


class Solution:
    def levelOrder(self,root):
        if not root:
            return []

        result = []
        # print("root: ",root.val)
        queue =deque([(root,0)])
        # print("queue: ",queue)
        while queue:
            size = len(queue)
            print("size: ",size)
            result.append([])

            for i in range(size):
                node,level = queue.popleft()
                print("node: ",node.val)
                result[level].append(node.val)

                if node.left:
                    queue.append((node.left, level+1))
                if node.right:
                    queue.append((node.right, level+1))
        return result

if __name__ == '__main__':
    a = Solution()
    node = Node(1)
    node.left = Node(2)
    node.left.left = Node(3)
    node.left.right = Node(9)
    node.right = Node(5)
    node.right.right = Node(6)
    root = node
    print(a.levelOrder(root))

618—搜索图中结点

描述

给定一张无向图,一个结点以及一个目标值,返回距离这个结点最近且值为目标值的结点,如果不能找到则返回 NULL。
在给出的参数中, 我们用 map 来存结点的值

注意事项

保证答案唯一

样例

2------3  5
 \     |  | 
  \    |  |
   \   |  |
    \  |  |
    1 --4

给出 节点1,目标值为 50
有个哈希表的值为[3,4,10,50,50],表示:

节点1的值为3
节点2的值为4
节点3的值为10
节点4的值为50
节点5的值为50

返回 节点4
实际上考的就是BFS模板,如果只存在一个最近点用下列代码即可,若存在几个则需分层,参考之前二叉树分层

#图+队列的层次遍历+set保存访问列表

#2019/8/23fuxi
from collections import deque
import sys
class UndirectedGraphNode:
    def __init__(self,x):
        self.label = x
        self.neighbors = []

class Solution:
    def searchNode(self,graph,values,node,target):
        if not graph or not values or not node.label:
            return None

        queue = deque([node])
        visited = set()
        while queue:
            node = queue.popleft()

            if values[node.label] == target:
                print(node.label)

                return node

            visited.add(node)
            for neighbor in node.neighbors:
                # print(node.label)

                if neighbor not in visited:

                    queue.append(neighbor)
        return None


if __name__ == '__main__':
    a = Solution()
    graph1 = UndirectedGraphNode(1)
    graph2 = UndirectedGraphNode(2)
    graph3 = UndirectedGraphNode(3)
    graph4 = UndirectedGraphNode(4)
    graph5 = UndirectedGraphNode(5)
    graph1.neighbors = [graph2,graph4]
    graph2.neighbors = [graph1,graph3]
    graph3.neighbors = [graph2,graph4]
    graph4.neighbors = [graph1,graph3,graph5]
    graph5.neighbors = [graph4]
    values = [3,4,5,50,50]
    target = 50

    a.searchNode(graph1,values,graph1,target)
  1. 课程表
    中文English
    现在你总共有 n 门课需要选,记为 0 到 n - 1.
    一些课程在修之前需要先修另外的一些课程,比如要学习课程 0 你需要先学习课程 1 ,表示为[0,1]
    给定n门课以及他们的先决条件,判断是否可能完成所有课程?

Example
例1:

输入: n = 2, prerequisites = [[1,0]]
输出: true
例2:

输入: n = 2, prerequisites = [[1,0],[0,1]]
输出: false

##拓扑排序+队列+入度数组+依赖查询字典
#2019/8/25

##算法思路
# -输入为一组顶点集合和课程依赖
#-初始化度数组,用于记录每个顶点的度是多少。初值设为0
#-初始化依赖字典,构建每个顶点和其被依赖的顶点的集合
#-首先准备一个队列,使用一个for 循环将所有度为0的点放入队列中,
#--使用一个while循环处理队列---
#-最后检查输出元素的个数是否和给定的顶点集合的顶点树相同,如果相同则返回True
from collections import deque

class Solution:

    def canFinish(self,numCourses,prerequisites):
        if numCourses <= 0 or not prerequisites:
            return True

        degrees =[0 for _ in range(numCourses)]
        # print("degree: ",degrees)
        ##依赖课程可以理解为下游课程
        
        edges = {i: [] for i in range(numCourses)}
        # print("edges: ", edges)
        for courseNo,preCourseNo in prerequisites:
            degrees[courseNo] += 1
            edges[preCourseNo].append(courseNo)


        queue = deque([])
        for courseNo in range(numCourses):
            if degrees[courseNo] == 0:
                queue.append(courseNo)

        count = 0
        while queue:
            courseNo = queue.popleft()
            count += 1
            for neighbor in edges[courseNo]:
                degrees[neighbor]-=1
                if degrees[neighbor] ==0:
                    queue.append(neighbor)
        return count == numCourses



if __name__ == '__main__':
    a = Solution()
    A = 2
    B = [[1,0]]
    print(a.canFinish(A,B))

  1. 安排课程
    中文English
    你需要去上n门九章的课才能获得offer,这些课被标号为 0 到 n-1 。
    有一些课程需要“前置课程”,比如如果你要上课程0,你需要先学课程1,我们用一个匹配来表示他们: [0,1]

给你课程的总数量和一些前置课程的需求,返回你为了学完所有课程所安排的学习顺序。

可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。

Example
例1:

输入: n = 2, prerequisites = [[1,0]]
输出: [0,1]
例2:

输入: n = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
输出: [0,1,2,3] or [0,2,1,3]

// An highlighted block
var foo = 'bar';
  1. 骑士的最短路线
    给定骑士在棋盘上的 初始 位置(一个2进制矩阵 0 表示空 1 表示有障碍物),找到到达 终点 的最短路线,返回路线的长度。如果骑士不能到达则返回 -1 。
 * <p>
 * 样例
 * [[0,0,0],
 * [0,0,0],
 * [0,0,0]]
 * source = [2, 0] destination = [2, 2] return 2
 * <p>
 * [[0,1,0],
 * [0,0,0],
 * [0,0,0]]
 * source = [2, 0] destination = [2, 2] return 6
 * <p>
 * [[0,1,0],
 * [0,0,1],
 * [0,0,0]]
 * source = [2, 0] destination = [2, 2] return -1
 * 说明
 * 如果骑士的位置为 (x,y),他下一步可以到达以下这些位置:
 * <p>
 * (x + 1, y + 2)
 * (x + 1, y - 2)
 * (x - 1, y + 2)
 * (x - 1, y - 2)
 * (x + 2, y + 1)
 * (x + 2, y - 1)
 * (x - 2, y + 1)
 * (x - 2, y - 1)
 * 注意事项
 * 起点跟终点必定为空.
 * 骑士不能穿过障碍物.
from collections import deque

class Point:
    def __init__(self,a=0,b=0):
        self.x = a
        self.y = b

#宽度优先搜索
class Solution:
    def shortestPath(self,grid,source,destination):
        if not grid:
            return -1

        queue = deque([(source,0)])
        visited = set()
        dirs = [
            (1,2),
            (1,-2),
            (-1,2),
            (-1,-2),
            (2,1),
            (2,-1),
            (-2,1),
            (-2,-1)
        ]
        while queue:
            point,depth = queue.popleft()
            # print(point.x)
            visited.add((point.x,point.y))
            if point.x == destination.x and point.y == destination.y:
                return depth

            for dx,dy in dirs:
                nx = point.x +dx
                ny = point.y +dy
                if self.check(grid,nx,ny,visited):
                    queue.append((Point(nx,ny),depth+1))
        return -1

    def check(self,grid,x,y,visited):
        m,n =len(grid),len(grid[0])
        if x < 0 or x>=m or y < 0 or y >= n or (x,y) in visited or grid[x][y] == 1:
            return False
        return True

if __name__ == '__main__':
    a = Solution()
    grid = [[0,0,0],[0,0,0],[0,0,0]]
    print(len(grid))
    print(len(grid[0]))
    source = Point(2,0)
    destination = Point(2,2)
    print(a.shortestPath(grid,source,destination))

598—僵尸矩阵
题目

给一个二维网格,每一个格子都有一个值,2 代表墙,1 代表僵尸,0 代表人类(数字 0, 1, 2)。僵尸每天可以将上下左右最接近的人类感染成僵尸,但不能穿墙。将所有人类感染为僵尸需要多久,如果不能感染所有人则返回 -1。

样例

给一个矩阵:

0 1 2 0 0
1 0 0 2 1
0 1 0 0 0

返回 2

  1. 克隆图
    中文English
    克隆一张无向图. 无向图的每个节点包含一个 label 和一个列表 neighbors. 保证每个节点的 label 互不相同.

你的程序需要返回一个经过深度拷贝的新图. 新图和原图具有同样的结构, 并且对新图的任何改动不会对原图造成任何影响.

Example
样例1

输入:
{1,2,4#2,1,4#4,1,2}
输出:
{1,2,4#2,1,4#4,1,2}
解释:

1------2  
 \     |  
  \    |  
   \   |  
    \  |  
      4   

Clarification
关于无向图的表示: http://www.lintcode.com/help/graph/

Notice
你需要返回与给定节点具有相同 label 的那个节点.

  1. 图是否是树
    中文English
    给出 n 个节点,标号分别从 0 到 n - 1 并且给出一个 无向 边的列表 (给出每条边的两个顶点), 写一个函数去判断这张`无向`图是否是一棵树

Example
样例 1:

输入: n = 5 edges = [[0, 1], [0, 2], [0, 3], [1, 4]]
输出: true.
样例 2:

输入: n = 5 edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]]
输出: false.
Notice
你可以假设我们不会给出重复的边在边的列表当中. 无向边 [0, 1] 和 [1, 0] 是同一条边, 因此他们不会同时出现在我们给你的边的列表当中。

  1. 将二叉树按照层级转化为链表
    中文English
    给一棵二叉树,设计一个算法为每一层的节点建立一个链表。也就是说,如果一棵二叉树有 D 层,那么你需要创建 D 条链表。

Example
样例 1:

输入: {1,2,3,4}
输出: [1->null,2->3->null,4->null]
解释:

        1
       / \
      2   3
     /
    4

样例 2:

输入: {1,#,2,3}
输出: [1->null,2->null,3->null]
解释:

  1
     \
      2
     /
    3

624 移除子串
描述

给出一个字符串 s 以及 n 个子串。你可以从字符串 s 中移除 n 个子串中的任意一个,使得剩下来 s 的长度最小,输出这个最小长度。

样例

给出 s = ccdaabcdbb,子串为 [“ab”,“cd”]
返回 2.

解释

ccdaabcdbb -> ccdacdbb -> cabb -> cb (长度为 2)

  1. 序列重构
    中文English
    判断是否序列 org 能唯一地由 seqs重构得出. org是一个由从1到n的正整数排列而成的序列,1 ≤ n ≤ 10^4。 重构表示组合成seqs的一个最短的父序列 (意思是,一个最短的序列使得所有 seqs里的序列都是它的子序列).
    判断是否有且仅有一个能从 seqs重构出来的序列,并且这个序列是org。

Example
例1:

输入:org = [1,2,3], seqs = [[1,2],[1,3]]
输出: false
解释:
[1,2,3] 并不是唯一可以被重构出的序列,还可以重构出 [1,3,2]
例2:

输入: org = [1,2,3], seqs = [[1,2]]
输出: false
解释:
能重构出的序列只有 [1,2].
例3:

输入: org = [1,2,3], seqs = [[1,2],[1,3],[2,3]]
输出: true
解释:
序列 [1,2], [1,3], 和 [2,3] 可以唯一重构出 [1,2,3].
例4:

输入:org = [4,1,5,2,6,3], seqs = [[5,2,6,3],[4,1,5,2]]
输出:true

531 六度分离
原题

六度分离是一个哲学问题,说的是每个人每个东西可以通过六步或者更少的步数建立联系。
现在给你一个友谊关系,查询两个人可以通过几步相连,如果不相连返回 -1

样例
给出图

1------2-----4
 \          /
  \        /
   \--3--/

{1,2,3#2,1,4#3,1,4#4,2,3} s = 1, t = 4 返回 2
给出图二

1      2-----4
             /
           /
          3

{1#2,4#3,4#4,2,3} s = 1, t = 4 返回 -1

  1. 拓扑排序
    中文English
    给定一个有向图,图节点的拓扑排序定义如下:

对于图中的每一条有向边 A -> B , 在拓扑排序中A一定在B之前.
拓扑排序中的第一个节点可以是图中的任何一个没有其他节点指向它的节点.
针对给定的有向图找到任意一种拓扑排序的顺序.

Example
例如以下的图:
在这里插入图片描述

拓扑排序可以为:

[0, 1, 2, 3, 4, 5]
[0, 2, 3, 1, 5, 4]
Challenge
能否分别用BFS和DFS完成?

Clarification
有关图的表示详情请看这里

Notice
你可以假设图中至少存在一种拓扑排序

  1. 单词接龙
    中文English
    给出两个单词(start和end)和一个字典,找出从start到end的最短转换序列,输出最短序列的长度。

变换规则如下:

每次只能改变一个字母。
变换过程中的中间单词必须在字典中出现。(起始单词和结束单词不需要出现在字典中)
Example
样例 1:

输入:start = “a”,end = “c”,dict =[“a”,“b”,“c”]
输出:2
解释:
“a”->“c”
样例 2:

输入:start =“hit”,end = “cog”,dict =[“hot”,“dot”,“dog”,“lot”,“log”]
输出:5
解释:
“hit”->“hot”->“dot”->“dog”->“cog”
Notice
如果不存在这样的转换序列,返回 0。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。

  1. 二叉树的层次遍历 II
    中文English
    给出一棵二叉树,返回其节点值从底向上的层次序遍历(按从叶节点所在层到根节点所在的层遍历,然后逐层从左往右遍历)

Example
例1:

输入:
{1,2,3}
输出:
[[2,3],[1]]
解释:

    1
   / \
  2   3

它将被序列化为 {1,2,3}
层次遍历
例2:

输入:
{3,9,20,#,#,15,7}
输出:
[[15,7],[9,20],[3]]
解释:

    3
   / \
  9  20
    /  \
   15   7

它将被序列化为 {3,9,20,#,#,15,7}
层次遍历

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值