BFS
简单
1、111. 二叉树的最小深度 https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/
考点:
1、一层一层遍历,直到满足要求
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def minDepth(self, root: TreeNode) -> int: if not root: return 0 global result result = None def helper(cur_list, layer): global result tmp = [] for cur in cur_list: # 叶子节点 if cur.left == None and cur.right == None: result = layer return if cur.left: tmp.append(cur.left) if cur.right: tmp.append(cur.right) helper(tmp, layer+1) start = [] start.append(root) helper(start, 1) return result
2、559. N叉树的最大深度 https://leetcode-cn.com/problems/maximum-depth-of-n-ary-tree/
考点:(同上)
""" # Definition for a Node. class Node: def __init__(self, val=None, children=None): self.val = val self.children = children """ class Solution: def maxDepth(self, root: 'Node') -> int: global result result = 0 def helper(last_list, layer): next_list = [] for cur in last_list: for child in cur.children: if child: next_list.append(child) if not next_list: global result result = layer return helper(next_list, layer+1) if not root: return 0 helper([root], 1) return result
3、剑指 Offer 32 - II. 从上到下打印二叉树 II https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/
考点:
1、BFS,从上到下 从左到右打印节点
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def levelOrder(self, root: TreeNode) -> List[List[int]]: result = [] def bfs(cur_list): next_list = [] cur_val = [] for cur in cur_list: if cur: cur_val.append(cur.val) next_list.append(cur.left) next_list.append(cur.right) if cur_val: result.append(cur_val) if next_list: bfs(next_list) bfs([root]) return result
3、993. 二叉树的堂兄弟节点 https://leetcode-cn.com/problems/cousins-in-binary-tree/
考点:
1、需要考虑二叉树层数关系,使用BFS
2、判断堂兄弟关系,引入一个列表表示当前已经遍历过的堂兄弟
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def check(self, cur, old_val, x, y): if cur.left and ((x == cur.left.val and y in old_val) or (y == cur.left.val and x in old_val) ): return True if cur.right and ((x == cur.right.val and y in old_val) or (y == cur.right.val and x in old_val) ): return True def refresh_old_val(self, cur, old_val, next_list): if cur.left: old_val.append(cur.left.val) next_list.append(cur.left) if cur.right: old_val.append(cur.right.val) next_list.append(cur.right) def isCousins(self, root: TreeNode, x: int, y: int) -> bool: global result result = False def bfs(cur_list): next_list = [] old_val = [] for cur in cur_list: cur_children = [] if self.check(cur, old_val, x, y): global result result = True return self.refresh_old_val(cur, old_val, next_list) if next_list: bfs(next_list) bfs([root]) return result
4. 690. 员工的重要性 https://leetcode-cn.com/problems/employee-importance/
考点:
1、引入字典数据结构,便于查找
2、每个递归生成新的列表,用于BFS查找
""" # Definition for Employee. class Employee: def __init__(self, id: int, importance: int, subordinates: List[int]): self.id = id self.importance = importance self.subordinates = subordinates """ class Solution: def getImportance(self, employees: List['Employee'], id: int) -> int: global imports imports = 0 child_employ = [] employ_dict = {} # get employ for employ in employees: employ_dict[employ.id] = employ def bfs(employees_list): global imports next_employee_list = [] for employ in employees_list: imports += employ_dict[employ].importance if employ_dict[employ].subordinates: next_employee_list.extend(employ_dict[employ].subordinates) if next_employee_list: bfs(next_employee_list) # get child employ bfs([id]) return imports
5.剑指 Offer 32 - III. 从上到下打印二叉树 III https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-iii-lcof/
考点:
1、典型BFS
2、引入一个boolen变量标志当前行打印正序还是逆序
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def levelOrder(self, root: TreeNode) -> List[List[int]]: result = [] global left_right left_right = True def bfs(layer_list): layer_result = [] next_list = [] for layer in layer_list: layer_result.append(layer.val) if layer.left: next_list.append(layer.left) if layer.right: next_list.append(layer.right) global left_right if left_right: result.append(layer_result) left_right = False else: layer_result.reverse() result.append(layer_result) left_right = True if next_list: bfs(next_list) if not root: return [] bfs([root]) return result
6. 剑指 Offer 32 - I. 从上到下打印二叉树 https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/
考点:
1、bfs遍历二叉树每一层
2、需要考虑输入为空树情况
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def levelOrder(self, root: TreeNode) -> List[int]: result = [] def bfs(layer_list): layer_result = [] next_layer = [] for layer in layer_list: layer_result.append(layer.val) if layer.left: next_layer.append(layer.left) if layer.right: next_layer.append(layer.right) result.extend(layer_result) if next_layer: bfs(next_layer) if not root: return [] bfs([root]) return result
7、542. 01 矩阵 https://leetcode-cn.com/problems/01-matrix/
考点
1、按照先设置距离为0的所有位置,然后BFS找所有距离为1的位置,一直迭代下去
2、注意,生成二维数组,不能使用[-1] * col * row, 应该使用 [[-1] * col for i in range(row)] 生成二维数据
class Solution: def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]: row = len(matrix) col = len(matrix[0]) result = [[-1] * col for i in range(row)] global result_rest result_rest = row * col zero_list = [] # print(result) # 初始化数组 for i in range(row): for j in range(col): if matrix[i][j] == 0: # print(i, j) zero_list.append((i, j)) result[i][j] = 0 result_rest -= 1 # print(result) # print(result) def bfs(layer_list, val): global result_rest # print(result) if result_rest == 0: return next_list = [] for layer in layer_list: i, j = layer for ii, jj in [(i+1, j), (i-1, j), (i, j-1), (i, j+1)]: if 0 <= ii < row and 0 <= jj < col and result[ii][jj] == -1: result[ii][jj] = val + 1 next_list.append((ii, jj)) # global result_rest result_rest -= 1 bfs(next_list, val + 1) bfs(zero_list, 0) # print(result) return result
8、279. 完全平方数 https://leetcode-cn.com/problems/perfect-squares/
考点:
1、计算最小值,迭代后面值由前面值 确定,可以使用动态规划作态
2、同时 该类问题可以考虑使用BFS,即计算每步结果的列表,当结果列表有最终结果,返回结果即可
class Solution: def numSquares(self, n: int) -> int: selected_num = [] for i in range(1, int(n ** 0.5)+1): selected_num.append(i ** 2) print(selected_num) global result result = n if n in selected_num: return 1 def bfs(cur_list, cur_layer): next_list = set() for selected in selected_num: for cur in cur_list: next_list.add(selected + cur) if n in next_list: global result result = cur_layer + 1 return else: bfs(next_list, cur_layer + 1) bfs(selected_num, 1) return result
9.863. 二叉树中所有距离为 K 的结点 https://leetcode-cn.com/problems/all-nodes-distance-k-in-binary-tree/
考点:
1、BFS和DFS结合使用
2、计算出每个层次距离为1的关系字典表,然后 使用DFS计算响应距离为K的路径
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def distanceK(self, root: TreeNode, target: TreeNode, K: int) -> List[int]: relation = collections.defaultdict(list) def bfs(cur_list): next_list = [] for cur in cur_list: if cur.left: relation[cur.val].append(cur.left.val) relation[cur.left.val].append(cur.val) next_list.append(cur.left) if cur.right: relation[cur.val].append(cur.right.val) relation[cur.right.val].append(cur.val) next_list.append(cur.right) if next_list: bfs(next_list) bfs([root]) result = [] def dfs(cur_list, step): if step == K: result.append(cur_list[-1]) if relation.get(cur_list[-1]): for next_node in relation.get(cur_list[-1]): if next_node not in cur_list: new_cur_list = list(cur_list) new_cur_list.append(next_node) dfs(new_cur_list, step + 1) dfs([target.val], 0) return result
10.513. 找树左下角的值 https://leetcode-cn.com/problems/find-bottom-left-tree-value/
考点:
1、BFS遍历,知道都没有子节点
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def findBottomLeftValue(self, root: TreeNode) -> int: def bfs(cur_list): next_list = [] for cur in cur_list: # print(cur.val) if cur.left: next_list.append(cur.left) if cur.right: next_list.append(cur.right) if not next_list: # print("%%", cur_list[0]) return cur_list[0] else: return bfs(next_list) if not root: return None return bfs([root]).val
11、1391. 检查网格中是否存在有效路径 https://leetcode-cn.com/problems/check-if-there-is-a-valid-path-in-a-grid/
12、 1519. 子树中标签相同的节点数 https://leetcode-cn.com/problems/number-of-nodes-in-the-sub-tree-with-the-same-label/submissions/
考点:
1、先使用BFS建立单层关系,然后使用BFS查找更深层次关系,结果显示 时间超时
class Solution: def countSubTrees(self, n: int, edges: List[List[int]], labels: str) -> List[int]: relation = collections.defaultdict(list) def bfs(cur_list): if len(edges) == 0: return next_list = [] for cur in cur_list: for edge in list(edges): if cur == edge[0]: next_list.append(edge[1]) edges.remove(edge) relation[cur].append(edge[1]) elif cur == edge[1]: next_list.append(edge[0]) edges.remove(edge) relation[cur].append(edge[0]) if next_list: bfs(next_list) # 建立22之间关系 bfs([0]) def bfs_time(cur_list): next_list = [] for cur in cur_list: if relation[cur]: # print(relation[cur], relation[cur]) next_list.extend(relation[cur]) if next_list: next_list.extend(bfs_time(next_list)) return next_list # BFS计算子树次数 result = [1] * n for i in range(n): result[i] = bfs_time([i]) # print(result) # 计算重复个数 index_value = {} for i in range(n): index_value[i] = labels[i] # print(index_value) real_result = [1] * n for i in range(n): compare_value = index_value[i] tmp = 0 for j in result[i]: if compare_value == index_value[j]: tmp += 1 real_result[i] += tmp return real_result
13、515. 在每个树行中找最大值 https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/
考点:
1、bfs遍历每一层
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def largestValues(self, root: TreeNode) -> List[int]: result = [] def bfs(cur_list): next_list = [] for cur in cur_list: if cur.left: next_list.append(cur.left) if cur.right: next_list.append(cur.right) if next_list: value = [next_v.val for next_v in next_list] result.append(max(value)) bfs(next_list) if not root: return [] result.append(root.val) bfs([root]) return result
14、 752. 打开转盘锁 https://leetcode-cn.com/problems/open-the-lock/
考点:
1、该题为求最大值最小值,后一状态由前一状态推到出,可以想到使用动态规划做
2、该题我们同样考虑使用BFS来做,计算每步能得到所有字符串列表,当列表有目标字符串,则返回结果
class Solution: def openLock(self, deadends: List[str], target: str) -> int: history = [] global result result = -1 relation = {"0": ("1", "9"), "1": ("0", "2"), "2": ("1", "3"), "3": ("2", "4"), "4": ("3", "5"), "5": ("4", "6"), "6": ("5", "7"), "7": ("6", "8"), "8": ("7", "9"), "9": ("8", "0")} def change(string): # 变化各位置 result = [] for i in range(4): # print(string[i]) k, l = relation[string[i]] result.append(string[0:i]+k+string[i+1:]) result.append(string[0:i]+l+string[i+1:]) return result def bfs(cur_list, step): # print(cur_list, step) if target in cur_list: global result result = step return next_list = [] for cur in cur_list: change_strs = change(cur) for change_str in change_strs: if change_str not in history and change_str not in deadends: next_list.append(change_str) history.append(change_str) if next_list: bfs(next_list, step + 1) if "0000" in deadends: return -1 bfs(["0000"], 0) return result
上面答案会出现超限时间限制,这里有一个技巧,把代码中的list替换成set,通过
class Solution: def openLock(self, deadends: List[str], target: str) -> int: history = set(deadends) global result result = -1 relation = {"0": ("1", "9"), "1": ("0", "2"), "2": ("1", "3"), "3": ("2", "4"), "4": ("3", "5"), "5": ("4", "6"), "6": ("5", "7"), "7": ("6", "8"), "8": ("7", "9"), "9": ("8", "0")} def change(string): # 变化各位置 result = [] for i in range(4): # print(string[i]) k, l = relation[string[i]] result.append(string[0:i]+k+string[i+1:]) result.append(string[0:i]+l+string[i+1:]) return result def bfs(cur_list, step): # print(cur_list, step) if target in cur_list: global result result = step return next_list = [] for cur in cur_list: change_strs = change(cur) for change_str in change_strs: if change_str not in history: next_list.append(change_str) history.add(change_str) if next_list: bfs(next_list, step + 1) if "0000" in deadends: return -1 bfs(["0000"], 0) return result
15、994. 腐烂的橘子 https://leetcode-cn.com/problems/rotting-oranges/
考点:
1、典型的BFS题型,计算每一遍腐烂之后的苹果状态
class Solution: def orangesRotting(self, grid: List[List[int]]) -> int: all_bad = [] all_good = [] row = len(grid) col = len(grid[0]) for i in range(row): for j in range(col): if grid[i][j] == 1: all_good.append((i, j)) elif grid[i][j] == 2: all_bad.append((i, j)) # print(all_bad, all_good) def bfs(bad_list, step): next_list = [] for bad in bad_list: i, j = bad for ii, jj in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]: if 0 <= ii < row and 0 <= jj < col and (ii, jj) in all_good: next_list.append((ii, jj)) all_good.remove((ii, jj)) if next_list: return bfs(next_list, step+1) return step step = bfs(all_bad, 0) return -1 if all_good else step
15、126. 单词接龙 II
考点:
1、修改一个字符,即字符窜的某个字符为*,所以先对所有字符窜 生成 dict,key为某个匹配到全字符窜
2、使用BFS,计算每步可得到的字符窜,然后就超时了
3、注意,history使用set比使用list 效率高
4、每步使用pattern 表示已经跑过的类型, 如果已经跑过了,该类型的字符窜就肯定在结果列表里面,后续就不用跑该类型(剪枝)
class Solution: def findLadders(self, beginWord, endWord, wordList): word_dict = collections.defaultdict(list) for word in wordList: for i in range(len(word)): word_dict[word[:i] + "*" + word[i+1:]].append(word) global hist hist = set() def bfs(cur_lists, step): global hist next_list = [] bfs_result = [] for cur_list in cur_lists: if endWord in cur_list: bfs_result.append(cur_list) if bfs_result: return bfs_result tmp_history = set() for cur_list in cur_lists: for i in range(len(cur_list[-1])): pattern = cur_list[-1][:i] + "*" + cur_list[-1][i+1:] if pattern not in hist: next_words = word_dict.get(pattern) if next_words: for word in next_words: if word not in cur_list: new_cur_list = list(cur_list) new_cur_list.append(word) next_list.append(new_cur_list) tmp_history.add(pattern) hist = hist.union(tmp_history) print("-", hist) if next_list: return bfs(next_list, step+1) else: return [] return bfs([[beginWord]], 0)
16、210. 课程表 II
考点:
1、BFS,一层一层选取当前学习的课程
2、引入课表list,表示当前的依赖课程数目,当依赖的课程数目为0,就可以加到学习顺序列表中; 同时更新被依赖课程的课表list
class Solution: def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]: rela = [0] * numCourses relationed = collections.defaultdict(list) for prerequisite in prerequisites: i, j = prerequisite[0], prerequisite[1] rela[i] += 1 relationed[j].append(i) # print(rela, relationed) result = [] def bfs(): try: next_course = rela.index(0) result.append(next_course) rela[next_course] = -1 rela_delete = relationed[next_course] if rela_delete: for course in rela_delete: rela[course] -= 1 # print(rela, relationed) except: return bfs() bfs() return result if len(result) == numCourses else []
17、
考点:
1、先找出所有1的点; 然后使用BFS,一层一层找到连在一起的岛屿, 然后然后就超时了
class Solution: def numIslands(self, grid): # get all iland row = len(grid) col = len(grid[0]) ilands = [] for i in range(row): for j in range(col): if grid[i][j] == "1": ilands.append((i, j)) print(ilands) def bfs(cur_list): print(cur_list) next_list = [] for cur in cur_list: i, j = cur for ii, jj in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]: if 0 <= ii < row and 0 <= jj < col and grid[ii][jj] == "1"\ and (ii, jj) not in included: next_list.append((ii, jj)) included.append((ii, jj)) if next_list: bfs(next_list) included = [] nums = 0 for iland in ilands: if iland not in included: included.append(iland) nums += 1 # 扩展岛屿 bfs([iland]) return nums
老套路,把list转成set
class Solution: def numIslands(self, grid: List[List[str]]) -> int: # get all iland row = len(grid) col = len(grid[0]) ilands = [] for i in range(row): for j in range(col): if grid[i][j] == "1": ilands.append((i, j)) def bfs(cur_list): next_list = [] for cur in cur_list: i, j = cur for ii, jj in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]: if 0 <= ii < row and 0 <= jj < col and grid[ii][jj] == "1"\ and (ii, jj) not in included: next_list.append((ii, jj)) included.add((ii, jj)) if next_list: bfs(next_list) included = set() nums = 0 for iland in ilands: if iland not in included: included.add(iland) nums += 1 # 扩展岛屿 bfs([iland]) return nums
考点:
1、由于graph.length最大12,尝试对每一个节点开始,然后使用BFS一层一层路径遍历,然后就超时了
class Solution: def shortestPathLength(self, graph: List[List[int]]) -> int: # 由于graph.length比较小,使用BFS遍历 n = len(graph) global min_result, result min_result = n * 2 result = None def bfs(cur_lists): # print(cur_lists) next_list = [] for cur_list in cur_lists: if len(set(cur_list)) == n: global min_result, result if min_result > len(cur_list): min_result = len(cur_list) result = cur_list # print("****************", cur_list) return cur_list last_pos = cur_list[-1] next_pos = list(graph[last_pos]) # print("-", cur_list) # print(next_pos) if len(next_pos) >=2 and len(cur_list) >=2 and cur_list[-2] in next_pos: next_pos.remove(cur_list[-2]) # print(next_pos) for next_p in next_pos: new_cur_list = list(cur_list) new_cur_list.append(next_p) next_list.append(new_cur_list) if next_list: bfs(next_list) # start with i for i in range(n): # print("++++++++++++++", i) bfs([[i]]) # print("&", result) return min_result-1
继续优化,让遍历的层数 大于当前算出来的最小值,直接return, 时间超时,还差2个用例
class Solution: def shortestPathLength(self, graph: List[List[int]]) -> int: # 由于graph.length比较小,使用BFS遍历 n = len(graph) global min_result, result min_result = n * 2 result = None def bfs(cur_lists): # print(cur_lists) next_list = [] for cur_list in cur_lists: if len(set(cur_list)) == n: global min_result, result if min_result > len(cur_list): min_result = len(cur_list) result = cur_list # print("****************", cur_list) return cur_list if len(cur_list) >= min_result: return last_pos = cur_list[-1] next_pos = list(graph[last_pos]) # print("-", cur_list) # print(next_pos) if len(next_pos) >=2 and len(cur_list) >=2 and cur_list[-2] in next_pos: next_pos.remove(cur_list[-2]) # print(next_pos) for next_p in next_pos: new_cur_list = list(cur_list) new_cur_list.append(next_p) next_list.append(new_cur_list) if next_list: bfs(next_list) # start with i for i in range(n): # print("++++++++++++++", i) bfs([[i]]) # print("&", result) return min_result-1
继续优化,
19、
93. 复原IP地址
考点:
1、使用BFS,执行4个step之后,然后获取满足要求的结果(包含4组数据, 字符窜遍历到最后了)
class Solution: def restoreIpAddresses(self, s): if len(s) < 4: return [] # 返回值0:为正常,1为异常,且没有必要继续(超255,格式异常如001) def check(str): if str.startswith("0"): if str == "0": return 0 else: return 1 elif 0 < int(str) <= 255: return 0 else: return 1 result = [] def bfs(cur_list, step): next_list = [] for cur in cur_list: cur_str, start_index = cur if start_index < len(s): for i in range(start_index+1, len(s)+1): next_str = s[start_index:i] if check(next_str) == 0: next_list.append((cur_str + "." +next_str, i)) else: break print(cur_list, step) if step == 3: for next in next_list: next_str, next_index = next if next_index == len(s) and next_str.count(".") == 4: result.append(next_str[1:]) elif next_list: bfs(next_list, step+1) bfs([('', 0)], 0) return result