1. BFS模板,记住这5个:
  2. 1)针对树的BFS
  3. 1.1 无需分层遍历
  4. from collections import deque
  5.  
  6. def levelOrderTree(root):
  7. if not root:
  8. return
  9.  
  10. q = deque([root])
  11. while q:
  12. head = q.popleft()
  13. do something with this head node...
  14. if head.left:
  15. q.append(head.left)
  16. if head.right:
  17. q.append(head.right)
  18. return xxx
  19. 1.2 需要分层遍历
  20. def levelOrderTree(root):
  21. if not root:
  22. return
  23.  
  24. q = [root]
  25. while q:
  26. new_q = []
  27. for node in q: # 和上面代码相比 差异就在这里 和 deque
  28. do something with this layer nodes...
  29. if node.left:
  30. new_q.append(node.left)
  31. if node.right:
  32. new_q.append(node.right)
  33. q = new_q
  34. return xxx
  35.  
  36. 2)针对图的BFS
  37. 2.1 无需分层遍历
  38. from collections import deque
  39.  
  40. def bfs_graph(root):
  41. if not root:
  42. return
  43.  
  44. queue = deque([root])
  45. seen = set([root])
  46. while queue:
  47. head = queue.popleft()
  48. do something with this head...
  49. for neighbor in head.neighbors:
  50. if neighbor not in seen: # 和tree的区别无非就是多了一个是否访问过的判断
  51. seen.add(neighbor)
  52. queue.append(neighbor)
  53.   return xxx
  54.  
  55. 上述代码中:
  56. neighbor 表示从某个点 head 出发,可以走到的下一层的节点。
  57. set/seen 存储已经访问过的节点(已经丢到 queue 里去过的节点)
  58. queue 存储等待被拓展到下一层的节点
  59. set/seen queue 是一对好基友,无时无刻都一起出现,往 queue 里新增一个节点,就要同时丢到 set 里。
  60. 需要分层遍历的宽度搜先搜索
  61.  
  62. 2.2 需分层遍历
  63.  
  64. def bfs_graph(root):
  65. if not root:
  66. return []
  67.  
  68. q = [root]
  69. seen = set([root])
  70. while q:
  71. new_q = []
  72. for node in q:
  73. do something with this layer nodes...
  74. for neighbor in node.neighbors:
  75. if neighbor not in seen: # 和tree的区别无非就是多了一个是否访问过的判断
  76. seen.add(neighbor)
  77. new_q.append(neighbor)
  78. q = new_q
  79. return xxx
  80.  
  81. 3)拓扑排序
  82.  
  83. 记住下面的代码
  84. class Solution:
  85. """
  86. @param graph: A list of Directed graph node
  87. @return: Any topological order for the given graph.
  88. """
  89. def topSort(self, graph):
  90. node_to_indegree = self.get_indegree(graph)
  91.  
  92. # bfs
  93. order = []
  94. start_nodes = [n for n in graph if node_to_indegree[n] == 0]
  95. queue = collections.deque(start_nodes)
  96. while queue:
  97. node = queue.popleft()
  98. order.append(node)
  99. for neighbor in node.neighbors:
  100. node_to_indegree[neighbor] -= 1
  101. if node_to_indegree[neighbor] == 0:
  102. queue.append(neighbor)
  103.  
  104. return order
  105.  
  106. def get_indegree(self, graph):
  107. node_to_indegree = {x: 0 for x in graph}
  108.  
  109. for node in graph:
  110. for neighbor in node.neighbors:
  111. node_to_indegree[neighbor] += 1
  112.  
  113. return node_to_indegree
  114.  
  115. 算法流程
  116. 拓扑排序的算法是典型的宽度优先搜索算法,其大致流程如下:
  117. 统计所有点的入度,并初始化拓扑序列为空。
  118. 将所有入度为 0 的点,也就是那些没有任何依赖的点,放到宽度优先搜索的队列中
  119. 将队列中的点一个一个的释放出来,放到拓扑序列中,每次释放出某个点 A 的时候,就访问 A 的相邻点(所有A指向的点),并把这些点的入度减去 1
  120. 如果发现某个点的入度被减去 1 之后变成了 0,则放入队列中。
  121. 直到队列为空时,算法结束
  122.  
  123. 一些实际案例:
  124. https://www.cnblogs.com/bonelee/p/11724346.html

  

69. 二叉树的层次遍历

中文English

给出一棵二叉树,返回其节点值的层次遍历(逐层从左往右访问)

Example

样例 1:

  1. 输入:{1,2,3}
  2. 输出:[[1],[2,3]]
  3. 解释:
  4. 1
  5. / \
  6. 2 3
  7. 它将被序列化为{1,2,3}
  8. 层次遍历

样例 2:

  1. 输入:{1,#,2,3}
  2. 输出:[[1],[2],[3]]
  3. 解释:
  4. 1
  5. \
  6. 2
  7. /
  8. 3
  9. 它将被序列化为{1,#,2,3}
  10. 层次遍历

Challenge

挑战1:只使用一个队列去实现它

挑战2:用BFS算法来做

Notice

  • 首个数据为根节点,后面接着是其左儿子和右儿子节点值,"#"表示不存在该子节点。
  • 节点数量不超过20。
  1. """
  2. Definition of TreeNode:
  3. class TreeNode:
  4. def __init__(self, val):
  5. self.val = val
  6. self.left, self.right = None, None
  7. """
  8.  
  9. class Solution:
  10. """
  11. @param root: A Tree
  12. @return: Level order a list of lists of integer
  13. """
  14. def levelOrder(self, root):
  15. # write your code here
  16. if not root:
  17. return []
  18.  
  19. q = [root]
  20. result = []
  21. while q:
  22. children = []
  23. q2 = []
  24. for node in q:
  25. children.append(node.val)
  26. if node.left:
  27. q2.append(node.left)
  28. if node.right:
  29. q2.append(node.right)
  30. result.append(children)
  31. q = q2
  32. return result

71. 二叉树的锯齿形层次遍历

中文
English

给出一棵二叉树,返回其节点值的锯齿形层次遍历(先从左往右,下一层再从右往左,层与层之间交替进行)

样例

样例 1:

  1. 输入:{1,2,3}
  2. 输出:[[1],[3,2]]
  3. 解释:
  4. 1
  5. / \
  6. 2 3
  7. 它将被序列化为 {1,2,3}

样例 2:

  1. 输入:{3,9,20,#,#,15,7}
  2. 输出:[[3],[20,9],[15,7]]
  3. 解释:
  4. 3
  5. / \
  6. 9 20
  7. / \
  8. 15 7
  9. 它将被序列化为 {3,9,20,#,#,15,7}
  1. """
  2. Definition of TreeNode:
  3. class TreeNode:
  4. def __init__(self, val):
  5. self.val = val
  6. self.left, self.right = None, None
  7. """
  8.  
  9. class Solution:
  10. """
  11. @param root: A Tree
  12. @return: A list of lists of integer include the zigzag level order traversal of its nodes' values.
  13. """
  14. def zigzagLevelOrder(self, root):
  15. # write your code here
  16. if not root:
  17. return []
  18.  
  19. q = [root]
  20. result = []
  21. layer = 0
  22. while q:
  23. q2 = []
  24. values = []
  25. for node in q:
  26. values.append(node.val)
  27. if node.left:
  28. q2.append(node.left)
  29. if node.right:
  30. q2.append(node.right)
  31. if layer % 2 == 0:
  32. result.append(values)
  33. else:
  34. result.append(values[::-1])
  35. q = q2
  36. layer += 1
  37. return result

70. 二叉树的层次遍历 II

中文
English

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

样例

例1:

  1. 输入:
  2. {1,2,3}
  3. 输出:
  4. [[2,3],[1]]
  5. 解释:
  6. 1
  7. / \
  8. 2 3
  9. 它将被序列化为 {1,2,3}
  10. 层次遍历

例2:

  1. 输入:
  2. {3,9,20,#,#,15,7}
  3. 输出:
  4. [[15,7],[9,20],[3]]
  5. 解释:
  6. 3
  7. / \
  8. 9 20
  9. / \
  10. 15 7
  11. 它将被序列化为 {3,9,20,#,#,15,7}
  12. 层次遍历
  1. """
  2. Definition of TreeNode:
  3. class TreeNode:
  4. def __init__(self, val):
  5. self.val = val
  6. self.left, self.right = None, None
  7. """
  8.  
  9. class Solution:
  10. """
  11. @param root: A tree
  12. @return: buttom-up level order a list of lists of integer
  13. """
  14. def levelOrderBottom(self, root):
  15. # write your code here
  16. # write your code here
  17. if not root:
  18. return []
  19.  
  20. result = []
  21. q = [root]
  22. while q:
  23. new_q = []
  24. values = []
  25. for node in q:
  26. values.append(node.val)
  27. if node.left:
  28. new_q.append(node.left)
  29. if node.right:
  30. new_q.append(node.right)
  31. result.append(values)
  32. q = new_q
  33. return result[::-1]

137. 克隆图

中文
English

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

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

样例

样例1

  1. 输入:
  2. {1,2,4#2,1,4#4,1,2}
  3. 输出:
  4. {1,2,4#2,1,4#4,1,2}
  5. 解释:
  6. 1------2
  7. \ |
  8. \ |
  9. \ |
  10. \ |
  11. 4

说明

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

注意事项

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

  1. """
  2. Definition for a undirected graph node
  3. class UndirectedGraphNode:
  4. def __init__(self, x):
  5. self.label = x
  6. self.neighbors = []
  7. """
  8.  
  9. from collections import deque
  10.  
  11. class Solution:
  12. """
  13. @param: node: A undirected graph node
  14. @return: A undirected graph node
  15. """
  16. def cloneGraph(self, root):
  17. # write your code here
  18. if not root:
  19. return None
  20.  
  21. """
  22. 使用宽度优先搜索 BFS 的版本。
  23. 第一步:找到所有独一的点
  24. 第二步:复制所有的点,将映射关系存起来
  25. 第三步:找到所有的边,复制每一条边
  26. """
  27. nodes = self.get_unique_nodes(root)
  28. mapping_nodes = self.copy_nodes(nodes)
  29. self.copy_edges(nodes, mapping_nodes)
  30. return mapping_nodes[root]
  31.  
  32. def get_unique_nodes(self, root):
  33. q, seen = deque([root]), set([root])
  34. while q:
  35. node = q.popleft()
  36. for neighbor_node in node.neighbors:
  37. if neighbor_node not in seen:
  38. seen.add(neighbor_node)
  39. q.append(neighbor_node)
  40. return seen
  41.  
  42. def copy_nodes(self, nodes):
  43. return {node: UndirectedGraphNode(node.label) for node in nodes}
  44.  
  45. def copy_edges(self, nodes, mapping_nodes):
  46. for node in nodes:
  47. copied_node = mapping_nodes[node]
  48. for neighbor in node.neighbors:
  49. copied_node.neighbors.append(mapping_nodes[neighbor])

120. 单词接龙

中文
English

给出两个单词(startend)和一个字典,找出从startend的最短转换序列,输出最短序列的长度。

变换规则如下:

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

样例

样例 1:

  1. 输入:start = "a"end = "c"dict =["a","b","c"]
  2. 输出:2
  3. 解释:
  4. "a"->"c"

样例 2:

  1. 输入:start ="hit"end = "cog"dict =["hot","dot","dog","lot","log"]
  2. 输出:5
  3. 解释:
  4. "hit"->"hot"->"dot"->"dog"->"cog"

注意事项

  • 如果不存在这样的转换序列,返回 0。
  • 所有单词具有相同的长度。
  • 所有单词只由小写字母组成。
  • 字典中不存在重复的单词。
  • 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
  1. class Solution:
  2. """
  3. @param: start: a string
  4. @param: end: a string
  5. @param: dict: a set of string
  6. @return: An integer
  7. """
  8. def ladderLength(self, start, end, dict):
  9. dict.add(end)
  10. q = [start]
  11. visited = set([start])
  12.  
  13. distance = 0
  14. while q:
  15. distance += 1
  16. new_q = []
  17. for word in q:
  18. if word == end:
  19. return distance
  20.  
  21. for next_word in self.get_next_words(word):
  22. if next_word not in dict or next_word in visited:
  23. continue
  24. new_q.append(next_word)
  25. visited.add(next_word)
  26. q = new_q
  27.  
  28. return 0
  29.  
  30. # O(26 * L^2)
  31. # L is the length of word
  32. def get_next_words(self, word):
  33. words = []
  34. for i in range(len(word)):
  35. left, right = word[:i], word[i + 1:]
  36. for char in 'abcdefghijklmnopqrstuvwxyz':
  37. if word[i] == char:
  38. continue
  39. words.append(left + char + right)
  40. return words

  

  1.  

7. 二叉树的序列化和反序列化

中文
English

设计一个算法,并编写代码来序列化和反序列化二叉树。将树写入一个文件被称为“序列化”,读取文件后重建同样的二叉树被称为“反序列化”。

如何反序列化或序列化二叉树是没有限制的,你只需要确保可以将二叉树序列化为一个字符串,并且可以将字符串反序列化为原来的树结构。

样例

样例 1:

  1. 输入:{3,9,20,#,#,15,7}
  2. 输出:{3,9,20,#,#,15,7}
  3. 解释:
  4. 二叉树 {3,9,20,#,#,15,7},表示如下的树结构:
  5. 3
  6. / \
  7. 9 20
  8. / \
  9. 15 7
  10. 它将被序列化为 {3,9,20,#,#,15,7}

样例 2:

  1. 输入:{1,2,3}
  2. 输出:{1,2,3}
  3. 解释:
  4. 二叉树 {1,2,3},表示如下的树结构:
  5. 1
  6. / \
  7. 2 3
  8. 它将被序列化为 {1,2,3}

我们的数据是进行 BFS 遍历得到的。当你测试结果 Wrong Answer 时,你可以作为输入调试你的代码。

你可以采用其他的方法进行序列化和反序列化。

注意事项

对二进制树进行反序列化或序列化的方式没有限制,LintCode 将您的 serialize 输出作为 deserialize 的输入,它不会检查序列化的结果。

  1. """
  2. Definition of TreeNode:
  3. class TreeNode:
  4. def __init__(self, val):
  5. self.val = val
  6. self.left, self.right = None, None
  7. """
  8.  
  9. from collections import deque
  10.  
  11. class Solution:
  12. """
  13. @param root: An object of TreeNode, denote the root of the binary tree.
  14. This method will be invoked first, you should design your own algorithm
  15. to serialize a binary tree which denote by a root node to a string which
  16. can be easily deserialized by your own "deserialize" method later.
  17. """
  18. def serialize(self, root):
  19. # write your code here
  20. if not root:
  21. return []
  22.  
  23. q = deque([root])
  24. result = []
  25. while q:
  26. head = q.popleft()
  27. if head:
  28. result.append(str(head.val))
  29. q.append(head.left)
  30. q.append(head.right)
  31. else:
  32. result.append('#')
  33.  
  34. while result and result[-1] == '#':
  35. result.pop()
  36.  
  37. return result
  38.  
  39. """
  40. @param data: A string serialized by your serialize method.
  41. This method will be invoked second, the argument data is what exactly
  42. you serialized at method "serialize", that means the data is not given by
  43. system, it's given by your own serialize method. So the format of data is
  44. designed by yourself, and deserialize it here as you serialize it in
  45. "serialize" method.
  46. """
  47. def deserialize(self, data):
  48. # write your code here
  49. if not data:
  50. return None
  51.  
  52. root = TreeNode(data[0])
  53. q = deque([root])
  54. i = 1
  55. while q and i < len(data):
  56. head = q.popleft()
  57. if data[i] != '#':
  58. head.left = TreeNode(data[i])
  59. q.append(head.left)
  60. i += 1
  61. if data[i] != '#':
  62. head.right = TreeNode(data[i])
  63. q.append(head.right)
  64. i += 1
  65. return root

433. 岛屿的个数

中文
English

给一个 01 矩阵,求不同的岛屿的个数。

0 代表海,1 代表岛,如果两个 1 相邻,那么这两个 1 属于同一个岛。我们只考虑上下左右为相邻。

样例

样例 1:

  1. 输入:
  2. [
  3. [1,1,0,0,0],
  4. [0,1,0,0,1],
  5. [0,0,0,1,1],
  6. [0,0,0,0,0],
  7. [0,0,0,0,1]
  8. ]
  9. 输出:
  10. 3

样例 2:

  1. 输入:
  2. [
  3. [1,1]
  4. ]
  5. 输出:
  6. 1
  1. from collections import deque
  2.  
  3. class Solution:
  4. """
  5. @param grid: a boolean 2D matrix
  6. @return: an integer
  7. """
  8. def numIslands(self, grid):
  9. if not grid or not grid[0]:
  10. return 0
  11.  
  12. islands = 0
  13. visited = set()
  14. for i in range(len(grid)):
  15. for j in range(len(grid[0])):
  16. if grid[i][j] and (i, j) not in visited:
  17. self.bfs(grid, i, j, visited)
  18. islands += 1
  19.  
  20. return islands
  21.  
  22. def bfs(self, grid, x, y, visited):
  23. queue = deque([(x, y)])
  24. visited.add((x, y))
  25. while queue:
  26. x, y = queue.popleft()
  27. for delta_x, delta_y in [(1, 0), (0, -1), (-1, 0), (0, 1)]:
  28. next_x = x + delta_x
  29. next_y = y + delta_y
  30. if not self.is_valid(grid, next_x, next_y, visited):
  31. continue
  32. queue.append((next_x, next_y))
  33. visited.add((next_x, next_y))
  34.  
  35. def is_valid(self, grid, x, y, visited):
  36. n, m = len(grid), len(grid[0])
  37. if not (0 <= x < n and 0 <= y < m):
  38. return False
  39. if (x, y) in visited:
  40. return False
  41. return grid[x][y]

611. 骑士的最短路线

中文
English

给定骑士在棋盘上的 初始 位置(一个2进制矩阵 0 表示空 1 表示有障碍物),找到到达 终点 的最短路线,返回路线的长度。如果骑士不能到达则返回 -1

样例

例1:

  1. 输入:
  2. [[0,0,0],
  3. [0,0,0],
  4. [0,0,0]]
  5. source = [2, 0] destination = [2, 2]
  6. 输出: 2
  7. 解释:
  8. [2,0]->[0,1]->[2,2]

例2:

  1. 输入:
  2. [[0,1,0],
  3. [0,0,1],
  4. [0,0,0]]
  5. source = [2, 0] destination = [2, 2]
  6. 输出:-1

说明

如果骑士的位置为 (x,y),他下一步可以到达以下这些位置:

  1. (x + 1, y + 2)
  2. (x + 1, y - 2)
  3. (x - 1, y + 2)
  4. (x - 1, y - 2)
  5. (x + 2, y + 1)
  6. (x + 2, y - 1)
  7. (x - 2, y + 1)
  8. (x - 2, y - 1)

注意事项

起点跟终点必定为空.
骑士不能碰到障碍物.
路径长度指骑士走的步数.

  1. """
  2. Definition for a point.
  3. class Point:
  4. def __init__(self, a=0, b=0):
  5. self.x = a
  6. self.y = b
  7. """
  8.  
  9. DIRECTIONS = [
  10. (-2, -1), (-2, 1), (-1, 2), (1, 2),
  11. (2, 1), (2, -1), (1, -2), (-1, -2),
  12. ]
  13.  
  14. class Solution:
  15.  
  16. """
  17. @param grid: a chessboard included 0 (false) and 1 (true)
  18. @param source: a point
  19. @param destination: a point
  20. @return: the shortest path
  21. """
  22. def shortestPath(self, grid, source, destination):
  23. queue = collections.deque([(source.x, source.y)])
  24. distance = {(source.x, source.y): 0}
  25.  
  26. while queue:
  27. x, y = queue.popleft()
  28. if (x, y) == (destination.x, destination.y):
  29. return distance[(x, y)]
  30. for dx, dy in DIRECTIONS:
  31. next_x, next_y = x + dx, y + dy
  32. if (next_x, next_y) in distance:
  33. continue
  34. if not self.is_valid(next_x, next_y, grid):
  35. continue
  36. distance[(next_x, next_y)] = distance[(x, y)] + 1
  37. queue.append((next_x, next_y))
  38. return -1
  39.  
  40. def is_valid(self, x, y, grid):
  41. n, m = len(grid), len(grid[0])
  42.  
  43. if x < 0 or x >= n or y < 0 or y >= m:
  44. return False
  45.  
  46. return not grid[x][y]

djkstra最短路问题,其实就是bfs不分层的模板,无非就是将deque修改为heapq而已,heapq中记录了路径距离优先级(下面程序如果不要path则去掉即可)

  1. import heapq
  2.  
  3. def shortest_path(graph, start, end):
  4. queue,seen = [(0, start, [])], {start}
  5. while queue:
  6. cost, v, path = heapq.heappop(queue)
  7. path = path + [v]
  8. if v == end:
  9. return cost, path
  10. for (neighbor_node, c) in graph[v].items():
  11. if neighbor_node not in seen:
  12. seen.add(neighbor_node)
  13. heapq.heappush(queue, (cost + c, neighbor_node, path))
  14. return -1, []
  15.  
  16. graph = {
  17. 'a': {'w': 14, 'x': 7, 'y': 9},
  18. 'b': {'w': 9, 'z': 6},
  19. 'w': {'a': 14, 'b': 9, 'y': 2},
  20. 'x': {'a': 7, 'y': 10, 'z': 10},
  21. 'y': {'a': 9, 'w': 2, 'x': 10, 'z': 11},
  22. 'z': {'b': 6, 'x': 15, 'y': 11},
  23. }
  24. cost, path = shortest_path(graph, start='a', end='z')
  25. print(cost, path)

  

拓扑排序定义

在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序(英语:Topological sorting)。

  • 每个顶点出现且只出现一次;
  • 若A在序列中排在B的前面,则在图中不存在从B到A的路径。

也可以定义为:拓扑排序是对有向无环图的顶点的一种排序,它使得如果存在一条从顶点A到顶点B的路径,那么在排序中B出现在A的后面。

(来自 Wiki)

实际运用

拓扑排序 Topological Sorting 是一个经典的图论问题。他实际的运用中,拓扑排序可以做如下的一些事情:

  • 检测编译时的循环依赖
  • 制定有依赖关系的任务的执行顺序

拓扑排序不是一种排序算法

虽然名字里有 Sorting,但是相比起我们熟知的 Bubble Sort, Quick Sort 等算法,Topological Sorting 并不是一种严格意义上的 Sorting Algorithm。

确切的说,一张图的拓扑序列可以有很多个,也可能没有。拓扑排序只需要找到其中一个序列,无需找到所有序列。

入度与出度

在介绍算法之前,我们先介绍图论中的一个基本概念,入度出度,英文为 in-degree & out-degree。
在有向图中,如果存在一条有向边 A-->B,那么我们认为这条边为 A 增加了一个出度,为 B 增加了一个入度。

算法流程

拓扑排序的算法是典型的宽度优先搜索算法,其大致流程如下:

  1. 统计所有点的入度,并初始化拓扑序列为空。
  2. 将所有入度为 0 的点,也就是那些没有任何依赖的点,放到宽度优先搜索的队列中
  3. 将队列中的点一个一个的释放出来,放到拓扑序列中,每次释放出某个点 A 的时候,就访问 A 的相邻点(所有A指向的点),并把这些点的入度减去 1。
  4. 如果发现某个点的入度被减去 1 之后变成了 0,则放入队列中。
  5. 直到队列为空时,算法结束,

深度优先搜索的拓扑排序

深度优先搜索也可以做拓扑排序,不过因为不容易理解,也并不推荐作为拓扑排序的主流算法。

127. 拓扑排序

中文English

给定一个有向图,图节点的拓扑排序定义如下:

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

针对给定的有向图找到任意一种拓扑排序的顺序.

Example

 

Challenge

能否分别用BFS和DFS完成?

Notice

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

  1. """
  2. Definition for a Directed graph node
  3. class DirectedGraphNode:
  4. def __init__(self, x):
  5. self.label = x
  6. self.neighbors = []
  7. """
  8.  
  9. class Solution:
  10. """
  11. @param graph: A list of Directed graph node
  12. @return: Any topological order for the given graph.
  13. """
  14. def topSort(self, graph):
  15. node_to_indegree = self.get_indegree(graph)
  16.  
  17. # bfs
  18. order = []
  19. start_nodes = [n for n in graph if node_to_indegree[n] == 0]
  20. queue = collections.deque(start_nodes)
  21. while queue:
  22. node = queue.popleft()
  23. order.append(node)
  24. for neighbor in node.neighbors:
  25. node_to_indegree[neighbor] -= 1
  26. if node_to_indegree[neighbor] == 0:
  27. queue.append(neighbor)
  28.  
  29. return order
  30.  
  31. def get_indegree(self, graph):
  32. node_to_indegree = {x: 0 for x in graph}
  33.  
  34. for node in graph:
  35. for neighbor in node.neighbors:
  36. node_to_indegree[neighbor] += 1
  37.  
  38. return node_to_indegree

615. 课程表

中文
English

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

样例

例1:

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

例2:

  1. 输入: n = 2, prerequisites = [[1,0],[0,1]]
  2. 输出: false
  1. from collections import deque
  2.  
  3. class Solution:
  4. # @param {int} numCourses a total of n courses
  5. # @param {int[][]} prerequisites a list of prerequisite pairs
  6. # @return {boolean} true if can finish all courses or false
  7. def canFinish(self, numCourses, prerequisites):
  8. # Write your code here
  9. edges = {i: [] for i in range(numCourses)}
  10. degrees = [0 for i in range(numCourses)]
  11. for i, j in prerequisites:
  12. edges[j].append(i)
  13. degrees[i] += 1
  14.  
  15. queue, count = deque([]), 0
  16.  
  17. for i in range(numCourses):
  18. if degrees[i] == 0:
  19. queue.append(i)
  20.  
  21. while queue:
  22. node = queue.popleft()
  23. count += 1
  24.  
  25. for x in edges[node]:
  26. degrees[x] -= 1
  27. if degrees[x] == 0:
  28. queue.append(x)
  29.  
  30. return count == numCourses

  

BFS (1)算法模板 看是否需要分层 (2)拓扑排序——检测编译时的循环依赖 制定有依赖关系的任务的执行顺序 djkstra无非是将bfs模板中的deque修改为heapq的更多相关文章

  1. BZOJ_1916_[Usaco2010 Open]冲浪_分层图+拓扑排序+DP

    BZOJ_1916_[Usaco2010 Open]冲浪_分层图+拓扑排序+DP Description 受到秘鲁的马丘比丘的新式水上乐园的启发,Farmer John决定也为奶牛们建 一个水上乐园. ...

  2. 算法与数据结构(七) AOV网的拓扑排序

    今天博客的内容依然与图有关,今天博客的主题是关于拓扑排序的.拓扑排序是基于AOV网的,关于AOV网的概念,我想引用下方这句话来介绍: AOV网:在现代化管理中,人们常用有向图来描述和分析一项工程的计划 ...

  3. 算法与数据结构(七) AOV网的拓扑排序(Swift版)

    今天博客的内容依然与图有关,今天博客的主题是关于拓扑排序的.拓扑排序是基于AOV网的,关于AOV网的概念,我想引用下方这句话来介绍: AOV网:在现代化管理中,人们常用有向图来描述和分析一项工程的计划 ...

  4. 【数据结构与算法Python版学习笔记】图——拓扑排序 Topological Sort

    概念 很多问题都可转化为图, 利用图算法解决 例如早餐吃薄煎饼的过程 制作松饼的难点在于知道先做哪一步.从图7-18可知,可以首先加热平底锅或者混合原材料.我们借助拓扑排序这种图算法来确定制作松饼的步 ...

  5. (原创)BFS广度优先算法,看完这篇就够了

    BFS算法 上一篇文章讲解了DFS深度优先遍历的算法,我们说 DFS 顾名思义DEEPTH FIRET,以深度为第一标准来查找,以不撞南墙不回头的态度来发掘每一个点,这个算法思想get到了其实蛮简单. ...

  6. 第8.5节 Python类中的__new__方法和构造方法__init__关系深入剖析:执行顺序及参数关系案例详解

    上节介绍了__new__()方法这个比构造方法还重要的方法的语法,本节通过案例来详细剖析__new__()方法的细节以及它与构造方法之间的关系. 一.    案例说明 本节以圆Cir类为例来说明,为了 ...

  7. 图解:有向环、拓扑排序与Kosaraju算法

    图算法第三篇 图解:有向环.拓扑排序与Kosaraju算法 首先来看一下今天的内容大纲,内容非常多,主要是对算法思路与来源的讲解,图文并茂,希望对你有帮助~ 1.有向图的概念和表示 概念 有向图与上一 ...

  8. SQL语句中各个部分的执行顺序(转)

    原文链接:http://www.tuicool.com/articles/fERNv2 写在前面的话:有时不理解SQL语句各个部分执行顺序,导致理解上出现偏差,或者是书写SQL语句时随心所欲,所以有必 ...

  9. java中try{}catch{}和finally{}的执行顺序问题

     今天我给大家讲解一下java的的错误和异常处理机制以及相关异常的执行顺序问题.如有不足的地方,欢迎批评指正~ 1.首相简单介绍一下java中的错误(Error)和异常(Exception) 错误和异 ...

随机推荐

  1. 第8课 常量表达式(constexpr)

    一. const 和constexpr的区别 (一)修饰变量时,const为“运行期常量”,即运行期数据是只读的.而constexpr为“编译期”常量,这是const无法保证的.两者都是对象和函数接口 ...

  2. 免费https证书

    https://certbot.eff.org/lets-encrypt/ubuntuother-nginx https://ruby-china.org/topics/31942 https://l ...

  3. Ladon内网渗透扫描器PowerShell版

    程序简介 Ladon一款用于大型网络渗透的多线程插件化综合扫描神器,含端口扫描.服务识别.网络资产.密码爆破.高危漏洞检测以及一键GetShell,支持批量A段/B段/C段以及跨网段扫描,支持URL. ...

  4. StringToKenizer和Scanner的区别

    相同点: StringToKenizer类和Scanner类都可用于分解字符序列中的单词! 不同点: StringToKenizer类把分解出的全部字符串都存放到StringToKenizer对象的实 ...

  5. QT攻略——我在QT中遇到的那些坑

    (1)QUdpSocket接收数据 进入槽后,要用这种方式读取,否则可能会导致不发readyRead()信号 .while(udpSocket->bytesAvailable()){ udpSo ...

  6. 【题解】PERIOD - Period [POJ1961] [SP263]

    [题解]PERIOD - Period [POJ1961] [SP263] 在进入这道题之前,我们需要了解 kmp 算法 不知道的童鞋可以去看一下Silent_EAG(一个可爱的女孩纸)的讲解. 关于 ...

  7. Phoenix连接安全模式下的HBase集群

    Phoenix连接安全模式下的HBase集群 HBase集群开启安全模式(即启用kerberos认证)之后,用户无论是用HBase shell还是Phoenix去连接HBase都先需要通过kerber ...

  8. python卸载重新安装,一键安装卸载前的所有安装的第三方插件

    好多小可爱都有这样一个困扰,python有了一个大版本的更新,我也想更新,但是安装的好多第三方的库可怎么办呀,更新之后再去一个一个的安装,那可就烦死了. 在这里我来教大家如何快速去安装python更新 ...

  9. [Linux] - 服务器/VPS一键检测带宽、CPU、内存、负载、IO读写

    一.SuperBench.sh VPS/服务器一键检测带宽.CPU.内存.负载.IO读写等的脚本: wget -qO- https://raw.githubusercontent.com/oooldk ...

  10. java中创建线程的3种方法

    1.继承Thread类优点:可以直接使用Thread类中的方法,代码比较简单.缺点:继承Thread类之后不能继承其他类. 2.实现Runable接口优点:实现接口,比影响继承其他类或实现接口.缺点: ...