本文不再更新:
请到:
https://blog.youkuaiyun.com/Ejzq1/article/details/124522728
题目列表
DFS概述
众所周知,DFS是面试考察重点之一!
深度优先搜索属于图算法的一种,是一个针对图和树的遍历算法,英文缩写为DFS即Depth First Search,如下图所示。
下面列举了使用到DFS的题目:
题目
从根节点到叶节点的路径数字之和
给定一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。
每条从根节点到叶节点的路径都代表一个数字:
例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。
计算从根节点到叶节点生成的 所有数字之和 。
- 解题思路:
深度优先算法,递归调用dfs
对于以下情况:
- 叶子节点:最终结果 += 当前值*10 + 叶子值
- 非叶子节点:继续dfs
- 实现代码:
class Solution:
def dfs(node,num):
isLeaf = True
num *= 10
num+=node.val
if node.left: dfs(node.left,num);isLeaf=False
if node.right: dfs(node.right,num);isLeaf=False
if isLeaf:self.ans+=num
return
self.ans = 0
dfs(root,0)
return self.ans
- 细节:
递归中可以先判断是否是叶子节点
也可以存一个布尔值进行判断
单值二叉树
如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。
只有给定的树是单值二叉树时,才返回 true;否则返回 false。
- 解题思路
简单深度优先算法实例
- 实现代码
class Solution:
def isUnivalTree(self, root: TreeNode) -> bool:
dfs = lambda node: not node or node.val==root.val and dfs(node.left) and dfs(node.right)
return dfs(root)
细节:
利用lambda函数可以tricky实现深度优先算法
根据二叉树创建字符串
你需要采用前序遍历的方式,将一个二叉树转换成一个由括号和整数组成的字符串。
空节点则用一对空括号 “()” 表示。而且你需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。
- 解题思路
前序遍历和中序遍历本质都是
深度优先遍历+分情况讨论
-
情况1:叶子节点
直接返回叶子节点值 -
情况2:左有右无
省略右括号 -
情况3:左无右有
左括号不能省略 -
情况4:左右都有:
左右均遍历
可以发现情况3、4是可以进行合并的
- 实现代码
class Solution:
def tree2str(self, root: Optional[TreeNode]) -> str:
dfs = self.tree2str
if not root:return ""
if not root.left and not root.right:return str(root.val)
if not root.right:return f"{root.val}({dfs(root.left)})"
return f"{root.val}({dfs(root.left)})({dfs(root.right)})"
细节:
其中f-string可参照博客中python tricky技巧查看:
https://blog.youkuaiyun.com/Ejzq1/article/details/123584412
两数之和 IV 输入 BST
给定一个二叉搜索树 root 和一个目标结果 k,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。
- 解题思路
深度优先遍历整个二叉树,使用python的set进行存储
由于只有两个数,直接将remainder添加到set中
如果是多个数就需要把不同情况的remainder加到set中
- 实现代码:
class Solution:
def findTarget(self, root: Optional[TreeNode], k: int) -> bool:
s=set()
def dfs(node):
if not node:return False
if node.val in s:return True
s.add(k-node.val)
return dfs(node.left) or dfs(node.right)
return dfs(root)
细节:
python 中 dict 与 set 都是以hash方式存储的
时间复杂度为O(1)
左叶子之和
给定二叉树的根节点 root ,返回所有左叶子之和。
- 解题思路
标准DFS遍历即可
- 实现代码
class Solution:
def sumOfLeftLeaves(self, root: TreeNode) -> int:
def dfs(node,isLeft):
if not node:return 0
if isLeft and not node.left and not node.right:return node.val
return dfs(node.left,True)+dfs(node.right,False)
return dfs(root,False)
- 细节:
dfs传入是否是左节点即可
同理,求右节点的和也一样处理
前序遍历构造二叉搜索树
给定二叉树的根节点 root ,返回所有左叶子之和。
- 解题思路
给定一个整数数组,它表示BST(即 二叉搜索树 )的 先序遍历 ,构造树并返回其根。
保证 对于给定的测试用例,总是有可能找到具有给定需求的二叉搜索树。
二叉搜索树 是一棵二叉树,其中每个节点, Node.left 的任何后代的值 严格小于 Node.val , Node.right 的任何后代的值 严格大于 Node.val。
二叉树的 前序遍历 首先显示节点的值,然后遍历Node.left,最后遍历Node.right。
- 实现代码
class Solution:
def bstFromPreorder(self, preorder: List[int]) -> Optional[TreeNode]:
def dfs(left,right):
if left==right:return None
root = TreeNode(preorder[left])
mid = bisect.bisect(preorder[left:right],root.val)+left
root.left = dfs(left+1,mid)
root.right = dfs(mid,right)
return root
return dfs(0,len(preorder))
- 细节:
bisect.bisect函数:
在有序列表 seq 中查找 item 的位置,并且返回其 索引 (index),使得插入item后序列依然保持有序
底层实现是二分查找
迷你语法分析器
给定一个字符串 s 表示一个整数嵌套列表,实现一个解析它的语法分析器并返回解析的结果 NestedInteger 。
列表中的每个元素只可能是整数或整数嵌套列表
-
解题思路:
嵌套 -> 递归 -> 深度优先算法 -
实现代码:
class Solution:
def deserialize(self, s: str) -> NestedInteger:
index = 0
def dfs() -> NestedInteger:
nonlocal index
if s[index] == '[':
index += 1
ni = NestedInteger()
while s[index] != ']':
ni.add(dfs())
if s[index] == ',':index += 1
index += 1
return ni
else:
negative = False if s[index] != '-' else (index := index+1)!=0 or True
start = index
while index < len(s) and s[index].isdigit(): index += 1
num = int(s[start:index])
return NestedInteger(-num if negative else num)
return dfs()
- 细节:
python 3.8 支持 海象运算符 :=
代码简化:
negative = False if s[index] != '-' else (index := index+1)!=0 or True
原代码:
if s[index] != '-':
negative = False
else:
index+=1
negative = True
建立四叉树
给你一个 n * n 矩阵 grid ,矩阵由若干 0 和 1 组成。请你用四叉树表示该矩阵 grid 。
你需要返回能表示矩阵的 四叉树 的根结点。
注意,当 isLeaf 为 False 时,你可以把 True 或者 False 赋值给节点,两种值都会被判题机制 接受 。
四叉树数据结构中,每个内部节点只有四个子节点。此外,每个节点都有两个属性:
val:储存叶子结点所代表的区域的值。1 对应 True,0 对应 False;
isLeaf: 当这个节点是一个叶子结点时为 True,如果它有 4 个子节点则为 False 。
class Node {
public boolean val;
public boolean isLeaf;
public Node topLeft;
public Node topRight;
public Node bottomLeft;
public Node bottomRight;
}
-
解题思路:
一般建立树的题目都是使用递归算法 -
实现代码:
class Solution:
def construct(self, grid: List[List[int]]) -> 'Node':
def dfs(rowLeft,rowRight,colLeft,colRight):
if all(grid[i][j]==grid[rowLeft][colLeft] for i in range(rowLeft,rowRight) for j in range(colLeft,colRight)):return Node(grid[rowLeft][colLeft]==1,True)
rowMid = (rowLeft+rowRight)//2
colMid = (colLeft+colRight)//2
return Node(
True,
False,
dfs(rowLeft,rowMid,colLeft,colMid),
dfs(rowLeft,rowMid,colMid,colRight),
dfs(rowMid,rowRight,colLeft,colMid),
dfs(rowMid,rowRight,colMid,colRight),
)
return dfs(0,len(grid),0,len(grid[0]))
- 细节:
all() 函数只有里面的都是真才为真
也可以使用前缀和的方法保存preSum
但是可读性--