树的路径
1、 二叉树的所有路径(257)
题目描述:
给定一个二叉树,返回所有从根节点到叶子节点的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
题解一:递归
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def binaryTreePaths(self, root):
"""
:type root: TreeNode
:rtype: List[str]
"""
def construct_paths(root, path):
if root:
path += str(root.val)
if not root.left and not root.right: # 当前节点是叶子节点
paths.append(path) # 把路径加入到答案中
else:
path += '->' # 当前节点不是叶子节点,继续递归遍历
construct_paths(root.left, path)
construct_paths(root.right, path)
paths = []
construct_paths(root, '')
return paths
2、路径总和(112)—判断路径和是否等于一个数
题目描述:
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22,
返回 true
, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
题解一:递归
思路:
1、寻找一条以root为根的、总和等于sum的路径可以分解为寻找一条以root.left为根或者以root.right为根的、总和等于sum - root.val的路径。
2、随着递归,每经过一个路径上一个非叶子节点,要寻找的值就减去了当前节点的值;
3、当到达叶子节点时,已经构成一条完整路径,此时若要寻找的值恰好和叶子节点的值相同,说明找到了一条这样的路径。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def hasPathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: bool
"""
if root is None:#根结点为空
return False
if not root.left and not root.right:#根结点没有左右孩子
return sum==root.val
return self.hasPathSum(root.left,sum-root.val) or self.hasPathSum(root.right,sum-root.val)
-
时间复杂度: O ( N ) O(N) O(N),其中 N N N 是树的节点数。对每个节点访问一次。
-
空间复杂度: O ( H ) O(H) O(H),其中 H H H 是树的高度。空间复杂度主要取决于递归时栈空间的开销,最坏情况下,树呈现链状,空间复杂度为 O ( N ) O(N) O(N)。平均情况下树的高度与节点数的对数正相关,空间复杂度为 O ( log N ) O(\log N) O(logN)。
题解二:广度优先搜索/迭代
思路:
\quad \quad BFS 使用栈,存储将要遍历的节点,以及剩余路径和。如果该节点恰好是叶子节点,并且 路径和 正好等于 sum,说明找了解。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def hasPathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: bool
"""
if not root: return False
stack = [(root, sum - root.val)]
while stack:
cur_node, cur_sum = stack.pop()
if not cur_node.left and not cur_node.right and cur_sum == 0:
return True
if cur_node.left:
stack.append((cur_node.left, cur_sum - cur_node.left.val))
if cur_node.right:
stack.append((cur_node.right, cur_sum - cur_node.right.val))
return False
-
时间复杂度: O ( N ) O(N) O(N),其中 N N N 是树的节点数。对每个节点访问一次。
-
空间复杂度: O ( N ) O(N) O(N),其中 N N N 是树的节点数。
3、路径总和II(113)—找到所有路径总和等于给定目标和的路径。
题目描述:
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22,
题解一:深度优先搜索之递归
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def pathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: List[List[int]]
"""
self.result=[]
if not root:
return []
def dfs(root,tmp,sum):
if not root:
return
#叶子节点且值等于给定值
if not root.left and not root.right and root.val==sum:
tmp+=[root.val]
self.result.append(tmp)
dfs(root.left,tmp+[root.val],sum-root.val)
dfs(root.right,tmp+[root.val],sum-root.val)
dfs(root,[],sum)
return self.result
4、路径总和III(437)—统计路径和等于给定数的路径总量
题目描述:
【中等】
给定一个二叉树,它的每个结点都存放着一个整数值。
找出路径和等于给定数值的路径总数。
路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
示例:
思路分析
1、注意路径不一定以 根结点开头,也不一定以 叶子节点结尾,但是必须连续。
2、
题解一:深度优先搜索之递归
5、二叉树的直径(543)
题目描述:
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
示例 :
给定二叉树
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。
注意:两结点之间的路径长度是以它们之间边的数目表示。
知识点
1、路径长度:
\quad \quad
如果树的结点序列
n
1
,
n
2
,
.
.
.
,
n
k
n_1,n_2,...,n_k
n1,n2,...,nk有如下关系:结点
n
i
n_i
ni是
n
i
+
1
n_i+1
ni+1的双亲(1<=i<k),则把
n
1
,
n
2
,
.
.
.
,
n
k
n_1,n_2,...,n_k
n1,n2,...,nk称为一条由
n
i
n_i
ni至
n
k
n_k
nk的路径,路径上经过的边的个数称为路径长度。
2、直径长度:
\quad \quad 一棵二叉树的直径长度是任意两个结点路径长度中的最大值。
思路分析:
1、初想,二叉树的直径长度=左子树高度+右子树高度,直接求根结点的左子树高度,以及右子树高度,然后再将两者相加即可;
2、转而一想,如果直径长度不穿过根结点,就没办法想上面那样求了,应该考虑以任意一个结点为根的直径情况:左子树高度+右子树高度,然后再求其最大值即可。
3、左子树高度、右子树高度采用递归法求即可,思想见求树的深度这篇文章。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def diameterOfBinaryTree(self, root):
"""
:type root: TreeNode
:rtype: int
"""
self.result=0#结果初始化为0
def depth(node):
#如果为空结点,返回0
if not node: return 0
#左孩子为根的子树的高度
L=depth(node.left)
#右孩子为根的子树的高度
R=depth(node.right)
#更新结果为其最大值
self.result=max(self.result,L+R)
return max(L,R)+1
depth(root)
return self.result
复杂度分析
-
时间复杂度: O ( N ) O(N) O(N),其中 N N N 为二叉树的节点数,即遍历一棵二叉树的时间复杂度,每个结点只被访问一次。
-
空间复杂度: O ( H e i g h t ) O(Height) O(Height),其中 H e i g h t Height Height 为二叉树的高度。由于递归函数在递归过程中需要为每一层递归函数分配栈空间,所以这里需要额外的空间且该空间取决于递归的深度,而递归的深度显然为二叉树的高度,并且每次递归调用的函数里又只用了常数个变量,所以所需空间复杂度为 O ( H e i g h t ) O(Height) O(Height) 。