系列文章目录
leetcode刷题:第一周
leetcode刷题:第二周
leetcode刷题:二分查找
leetcode刷题:双指针
leetcode刷题:广度/深度优先搜索
前言
随着开学,博主学校实验课也开始开展,并且有道理课程最多的大二,再加上准备六月份考英语四级,时间就偷偷溜走了,博客和算法都有一些拉下来。
这周简单记录一些深度/广度优先遍历的搜题题
一、深度/广度优先遍历
1.岛屿数量
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:grid = [
[“1”,“1”,“1”,“1”,“0”],
[“1”,“1”,“0”,“1”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“0”,“0”,“0”]
]
输出:1
示例 2:
输入:grid = [
[“1”,“1”,“0”,“0”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“1”,“0”,“0”],
[“0”,“0”,“0”,“1”,“1”]
]
输出:3
class Solution:
def __init__(self):
self.grid = [
["1", "1", "1", "1", "0"],
["1", "1", "0", "1", "0"],
["1", "1", "0", "0", "0"],
["0", "0", "0", "0", "0"]
]
def dfs(self, grid, r, c):
grid[r][c] = 0
nr = len(grid)
nc = len(grid[0])
for x, y in [(r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)]:
if 0 <= x < nr and 0 <= y < nc and grid[x][y] == "1":
self.dfs(grid, x, y)
def numIslands(self):
grid = self.grid
# 算法部分
nr = len(grid)
nc = len(grid[0])
num_islands = 0
if nr == 0:
return 0
#遍历每一格,当出现岛屿进行深度优先遍历
for r in range(nr):
for c in range(nc):
if grid[r][c] == "1":
num_islands += 1
self.dfs(grid, r, c)
return num_islands
if __name__ == '__main__':
s=Solution()
p=s.numIslands()
print(p)
2.省份数量
有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。
示例 1:
输入:isConnected = [[1,1,0],[1,1,0],[0,0,1]]
输出:2
示例 2:
输入:isConnected = [[1,0,0],[0,1,0],[0,0,1]]
输出:3
class Solution:
def __init__(self):
self.isConnected = [[1, 1, 0], [1, 1, 0], [0, 0, 1]]
def findCircleNum(self):
isConnected = self.isConnected
# 算法结构(没看懂)
def dfs(i):
for j in range(provinces):
if isConnected[i][j] == 1 and j not in visited:
visited.add(j)
dfs(j)
provinces = len(isConnected)
visited = set()
circles = 0
for i in range(provinces):
if i not in visited:
dfs(i)
circles += 1
return circles
3.填充每个节点的下一个右侧节点指针 II
给定一个二叉树
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
进阶:
你只能使用常量级额外空间。
使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
示例:
输入:root = [1,2,3,4,5,null,7]
输出:[1,#,2,3,#,4,5,7,#]
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化输出按层序遍历顺序(由 next 指针连接),’#’ 表示每层的末尾。
class Node:
def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
self.val = val
self.left = left
self.right = right
self.next = next
class Solution:
def connect(self, root: 'Node') -> Node:
# 算法部分(没看懂)
if not root:
return None
cur = root
while cur:
dummy = Node(-1)
pre = dummy
while cur:
if cur.left:
pre.next = cur.left
pre = pre.next
if cur.right:
pre.next = cur.right
pre = pre.next
cur = cur.next
cur = dummy.next
return root
简单说明一下,第一次没看懂,同一父节点,左孩子指向父节点的右孩子,不同父节点,左孩子指向父节点的next(父节点的兄弟节点)的左孩子。
4.另一棵树的子树
给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
示例 1:
输入:root = [3,4,5,1,2], subRoot = [4,1,2]
输出:true
示例 2:
输入:root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]
输出:false
# 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 isSubtree(self, root: TreeNode, subRoot: TreeNode) -> bool:
return self.preorder(root, subRoot)
def preorder(self, root, subRoot):
if not root: return False
resleft = self.preorder(root.left, subRoot)
resright = self.preorder(root.right, subRoot)
# 如果 根节点就不同 就直接返回左右子树的结果 跳过这一个root所在的子树
if root.val != subRoot.val: return resleft or resright
# 如果 根节点相同 就可以开始一次判断
return resleft or resright or self.helper(root, subRoot)
def helper(self, root, subRoot):
# 保证 子树的构造相同
if not root and not subRoot:
return True
if not root or not subRoot:
return False
# 保证 子树的值 都是相同的
return root.val == subRoot.val and self.helper(root.left, subRoot.left) and self.helper(root.right, subRoot.right)
5.二进制矩阵中的最短路径
给你一个 n x n 的二进制矩阵 grid 中,返回矩阵中最短 畅通路径 的长度。如果不存在这样的路径,返回 -1 。
二进制矩阵中的 畅通路径 是一条从 左上角 单元格(即,(0, 0))到 右下角 单元格(即,(n - 1, n - 1))的路径,该路径同时满足下述要求:
路径途经的所有单元格都的值都是 0 。
路径中所有相邻的单元格应当在 8 个方向之一 上连通(即,相邻两单元之间彼此不同且共享一条边或者一个角)。
畅通路径的长度 是该路径途经的单元格总数。
示例 1:
输入:grid = [[0,1],[1,0]]
输出:2
示例 2:
输入:grid = [[0,0,0],[1,1,0],[1,1,0]]
输出:4
示例 3:
输入:grid = [[1,0,0],[1,1,0],[1,1,0]]
输出:-1
class Solution:
def __init__(self):
self.grid = [[0, 0, 0], [1, 1, 0], [1, 1, 0]]
def shortestPathBinaryMatrix(self):
grid = self.grid
# 算法部分
n = len(grid)
if grid[0][0] or grid[n - 1][n - 1] != 0:
return -1
if n == 1:
return 1
start = 1
dxy = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]]
x1 = 0
x2 = 0
que = [[x1, x2]]
while que:
#两层while 保证将上一次压入的全部弹出后在累加
m = len(que)
#采用广度优先遍历,最先找到几位最短路径
while m:
m -= 1
x, y = que.pop(0)
if x == n - 1 and y == n - 1:
return start
for dx, dy in dxy:
x1 = x + dx
x2 = y + dy
if 0 <= x1 < n and 0 <= x2 < n and grid[x1][x2] == 0:
grid[x1][x2] = 1
que.append([x1, x2])
start += 1
return -1
if __name__ == '__main__':
s = Solution()
p = s.shortestPathBinaryMatrix()
print(p)
6.被围绕的区域
给你一个 m x n 的矩阵 board ,由若干字符 ‘X’ 和 ‘O’ ,找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。
示例 1:
输入:board = [[“X”,“X”,“X”,“X”],[“X”,“O”,“O”,“X”],[“X”,“X”,“O”,“X”],[“X”,“O”,“X”,“X”]]
输出:[[“X”,“X”,“X”,“X”],[“X”,“X”,“X”,“X”],[“X”,“X”,“X”,“X”],[“X”,“O”,“X”,“X”]]
解释:被围绕的区间不会存在于边界上,换句话说,任何边界上的 ‘O’ 都不会被填充为 ‘X’。 任何不在边界上,或不与边界上的 ‘O’ 相连的 ‘O’ 最终都会被填充为 ‘X’。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。
示例 2:
输入:board = [[“X”]]
输出:[[“X”]]
class Solution:
def __init__(self):
self.board = [["X", "X", "X", "X"], ["X", "O", "O", "X"], ["X", "X", "O", "X"], ["X", "O", "X", "X"]]
def solve(self):
board = self.board
# 算法部分
if not board:
return
def dfs(x, y):
if not 0 <= x < n or not 0 <= y < m or board[x][y] != 'O':
return
board[x][y] = 'A'
dfs(x + 1, y)
dfs(x - 1, y)
dfs(x, y + 1)
dfs(x, y - 1)
n, m = len(board), len(board[0])
for i in range(n):
dfs(i, 0)
dfs(i, m - 1)
for i in range(m - 1):
dfs(0, i)
dfs(n - 1, i)
for i in range(n):
for j in range(m):
if board[i][j] == 'A':
board[i][j] = 'O'
elif board[i][j] == 'O':
board[i][j] = 'X'
遍历四个边界,把不惜要改变的从O变成A,剩下的O就都是需要填充的,然后遍历整个数组,将O编程X,A在变回O。
7.所有可能的路径
给你一个有 n 个节点的 有向无环图(DAG),请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序)
graph [i] 是一个从节点 i 可以访问的所有节点的列表(即从节点 i 到节点 graph[i][j]存在一条有向边)。
示例 1:
输入:graph = [[1,2],[3],[3],[]]
输出:[[0,1,3],[0,2,3]]
解释:有两条路径 0 -> 1 -> 3 和 0 -> 2 -> 3
示例 2:
输入:graph = [[4,3,1],[3,2,4],[3],[4],[]]
输出:[[0,4],[0,3,4],[0,1,3,4],[0,1,2,3,4],[0,1,4]]
class Solution:
def __init__(self):
self.graph = [[1, 2], [3], [3], []]
def allPathsSourceTarget(self):
graph = self.graph
# 算法目录
ans = []
stk = []
def dfs(x):
if x == len(graph) - 1:
ans.append(stk[:])
return
for y in graph[x]:
stk.append(y)
dfs(y)
stk.pop()
stk.append(0)
dfs(0)
return ans
总结
学校课程加重了,刷题可能要拉下一些了。