二叉树的所有路径
给你一个二叉树的根节点 root
,按 任意顺序 ,返回所有从根节点到叶子节点的路径。 叶子节点 是指没有子节点的节点。
属于自顶向下问题
解题思路:1.对于一个节点先将他的值放到路径字符串中
2.判断该节点是不是叶子节点:是叶子节点该路径到此为止,非叶子结点继续遍历
3.根据输出形式,答案输出为列表形式,每一个路径是字符串形式
def binaryTreePaths(self, root):
"""
:type root: TreeNode
:rtype: List[str]
"""
def allPath(root,path):
if root:
path+=str(root.val)
if not root.left and not root.right:
#叶子节点到此为止
paths.append(path)
else: #非叶子节点继续该路径探索
path+='->'
allPath(root.left,path)
allPath(root.right,path)
paths=[]
allPath(root,'')
return paths
路径总和
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
解题思路:1.确定返回一个列表,列表元素也是列表且是所有值组成的
2.该节点的值加入列表,减少目标和
3.判断是否退出循环:若退出则满足题意,将该元素添加到答案列表,若不是则继续遍历左右子树
class Solution:
def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
ret = list()
path = list()#列表内元素
def dfs(root: TreeNode, targetSum: int):
if not root:#空树
return
path.append(root.val)#把该节点的值加入
targetSum -= root.val#减少目标和
if not root.left and not root.right and targetSum == 0:#到达叶节点且目标和满足
ret.append(path[:])#该条路径作为元素添加到答案列表
dfs(root.left, targetSum)
dfs(root.right, targetSum)
path.pop()
dfs(root, targetSum)
return ret
路径总和
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
解题思路1:遍历。1.对于一个节点先判断到他为止是不是等于路径和,是路径和就加一
2.遍历左右子树,此时路径和要减去父节点的值
class Solution:
def pathSum(self, root: TreeNode, targetSum: int) -> int:
def rootSum(root, targetSum):#参数是当前节点和总和
if root is None:
return 0
ret = 0 #初始路径数目为0
if root.val == targetSum:#节点值等于总和,符合路径数目加一
ret += 1
ret += rootSum(root.left, targetSum - root.val)#计算左子树
ret += rootSum(root.right, targetSum - root.val)#计算右子树
return ret
if root is None:
return 0
ret = rootSum(root, targetSum)
ret += self.pathSum(root.left, targetSum)
ret += self.pathSum(root.right, targetSum)
return ret
解题思路2:前缀和,两节点的路径等于前缀和之差(自上往下)
1.遍历树计算出各个节点的前缀和
2.从根节点到p节点的距离是差值,那么从p1到p节点的距离一定是总和
class Solution:
def pathSum(self, root: TreeNode, targetSum: int) -> int:
prefix = collections.defaultdict(int)#用来计数的字典
prefix[0] = 1
def dfs(root, curr):#输入前缀和
if not root:
return 0
ret = 0
curr += root.val#记录当前前缀和
ret += prefix[curr - targetSum]#记录当前前缀和与总和差对应的次数
prefix[curr] += 1 #该前缀和出现的次数
ret += dfs(root.left, curr)
ret += dfs(root.right, curr)
prefix[curr] -= 1 #?
return ret
return dfs(root, 0)
从叶节点开始的最小字符串
给定一颗根结点为 root 的二叉树,树中的每一个结点都有一个 [0, 25] 范围内的值,分别代表字母 'a' 到 'z'。返回 按字典序最小 的字符串,该字符串从这棵树的一个叶结点开始,到根结点结束。注:字符串中任何较短的前缀在 字典序上 都是 较小 的:例如,在字典序上 "ab" 比 "aba" 要小。叶结点是指没有子结点的结点。
解题思路:创建所有可能的字符串,然后进行比较。自顶而下寻找,然后将字符串逆序
class Solution(object):
def smallestFromLeaf(self, root):
self.ans = "~"
def dfs(node, A):
if node: #节点存在,将该节点值所代表的字母存入序列A
A.append(chr(node.val + ord('a')))
if not node.left and not node.right: #是叶节点结束寻找,开始比较
self.ans = min(self.ans, "".join(reversed(A)))#将序列逆转,每次都与上一个比较取最小值
dfs(node.left, A)
dfs(node.right, A)
A.pop()
dfs(root, [])
return self.ans
二叉树中最大路径和
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
给你一个二叉树的根节点 root ,返回其 最大路径和
解题思路:非自顶向下。对路径上的节点node来说有三种情况:
1.nodeleft+node有最大路径和
2.noderight+node有最大路径和
3.noderight+nodeleft+node有最大路径和
要注意第三种情况当出现负数路径直接舍弃
def MaxPath():
def dfs(node):
if !node:
return 0;#空树
left_max = max(0, dfs(node->left));#寻找左子树的最长路径,是负数取0
right_max = max(0, dfs(node->right));#寻找右子树最长路径,是负数取0
lnr_sum = left_max + node->val + right_max;#对应情况三
max_sum = max(max_sum, lnr_sum);#计算三种情况中最大路径和
ret = node->val + max(left_max, right_max);#向上一个节点返回该节点单边最大路径和
return ret;
return max_sum
最长同值路径
给定一个二叉树的 root ,返回 最长的路径的长度 ,这个路径中的 每个节点具有相同值 。 这条路径可以经过也可以不经过根节点。
两个节点之间的路径长度 由它们之间的边数表示。
解题思路:
class Solution:
def longestUnivaluePath(self, root: Optional[TreeNode]) -> int:
maxans = 0
def dfs(node: Optional[TreeNode]) -> int:
if node is None:#空树
return 0
left = dfs(node.left)#计算左子树的最长路径
right = dfs(node.right)#计算右子树的最长路径
left1 = left + 1 if node.left and node.left.val == node.val else 0
#只有当子树存在并且同值时路径长度加一,否则为0
right1 = right + 1 if node.right and node.right.val == node.val else 0
nonlocal maxans #nonlocal修改嵌套函数中上一级的局部变量
maxans= max(maxans, left1 + right1)
return max(left1, right1) #将当前左右子树最长路径返回给父节点
dfs(root)
return ans
二叉树直径
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
解题思路:
一条路径的长度为该路径经过的节点数减一,所以求直径(即求路径长度的最大值)等效于求路径经过节点数的最大值减一。任意一个node所在的路径是其左子树路径加上右子树路径
class Solution:
def diameterOfBinaryTree(self, root: TreeNode) -> int:
self.ans = 1
def depth(node):
if not node: # 访问到空节点了,返回0
return 0
L = depth(node.left) # 左儿子为根的子树的深度
R = depth(node.right) # 右儿子为根的子树的深度
self.ans = max(self.ans, L + R + 1) #节点数是左右深度加上自身
return max(L, R) + 1 # 返回该节点为根的子树的深度
depth(root)
return self.ans - 1 #路径长度就是节点数-1