python解leetcode二叉树(2)

    1. 相同的树 (两棵树是否相同)
    1. 二叉树的最大深度
    1. 二叉树的最小深度
    1. 路径总和 (找出树的两个节点之间的最长距离)
    1. 路径总和 II (找出和为某一值的路径)
    1. 二叉树中的最大路径和
    1. 路径总和 III
    1. 求根到叶子节点数字之和(找所有路径)
    1. 二叉树的所有路径
    1. 二叉树的直径
    1. 最长同值路径
    1. 二叉搜索树结点最小距离
    1. 二叉搜索树的范围和

给定两个二叉树,编写一个函数来检验它们是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例 1:

1
2
3
4
5
6
7
输入:       1         1
/ /
2 3 2 3

[1,2,3], [1,2,3]

输出: true

示例 2:

1
2
3
4
5
6
7
输入:      1          1
/
2 2

[1,2], [1,null,2]

输出: false

示例 3:

1
2
3
4
5
6
7
输入:       1         1
/ /
2 1 1 2

[1,2,1], [1,1,2]

输出: false

方法:递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None

class :
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
if not p and not q:
return True
if not p or not q:
return False
if p.val == q.val:
return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
else:
return False

104.二叉树的最大深度

LeetCode 104. Maximum Depth of Binary Tree

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例: 给定二叉树 [3,9,20,null,null,15,7],

1
2
3
4
5
  3
/
9 20
/
15 7

返回它的最大深度 3 。

方法一:深度优先搜索

深度优先搜索(DFS),递归求解。

1
2
3
4
5
class :
def maxDepth(self, root: TreeNode) -> int:
if not root:
return 0
return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))

方法二:广度优先搜索

广度优先搜索(BFS),利用队列求解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class :
def maxDepth(self, root: TreeNode) -> int:
if not root:
return 0

depth = 0
q = [root]
while len(q) != 0:
depth += 1
for _ in range(len(q)):
if q[0].left:
q.append(q[0].left)
if q[0].right:
q.append(q[0].right)
del q[0]
return depth

111. 二叉树的最小深度

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明: 叶子节点是指没有子节点的节点。

示例:

1
2
3
4
5
6
7
8
给定二叉树 [3,9,20,null,null,15,7],

3
/
9 20
/
15 7
返回它的最小深度  2.

方法:递归 + BFS

发现这层有个叶子的话,就直接返回就行了 叶子的深度是1

1
2
3
4
5
6
7
8
9
10
11
class :
def minDepth(self, root: TreeNode) -> int:
if not root:
return 0 # 当root为空的时候直接返回0
left = self.minDepth(root.left)
right = self.minDepth(root.right)
if not left:# 判断树的深度应该到叶子节点,也就是左右子结点都为空的那个结点
return right + 1
if not right:
return left + 1
return 1 + min(left, right)

112.路径总和

LeetCode 112. Path Sum

给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

说明: 叶子节点是指没有子节点的节点。

示例: 给定如下二叉树,以及目标和 sum = 22,

1
2
3
4
5
6
7
      5
/
4 8
/ /
11 13 4
/
7 2 1

返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。

方法一:DFS + 递归

用深度优先搜索(DFS)遍历所有可能的从根到叶的路径,要注意每深一层要从和中减去相应节点的数值。下面是递归实现的代码。

1
2
3
4
5
6
7
8
class :
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
if not root:
return False
if root.left or root.right:
return self.hasPathSum(root.left, sum-root.val) or self.hasPathSum(root.right, sum-root.val)
else:
return True if sum == root.val else False

方法二:DFS + 栈

DFS的非递归实现,用栈实现。

1
2
3
4
5
6
7
8
9
10
11
class Solution:
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
stack = [(root, sum)]
while len(stack) != 0:
node, tmp_sum = stack.pop()
if node:
if not node.left and not node.right and node.val == tmp_sum:
return True
stack.append((node.right, tmp_sum-node.val))
stack.append((node.left, tmp_sum-node.val))
return False

方法三:BFS + 队列

1
2
3
4
5
6
7
8
9
10
11
class Solution:
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
queue = [(root, sum)]
while len(queue) != 0:
node, tmp_sum = queue.pop()
if node:
if not node.left and not node.right and node.val == tmp_sum:
return True
queue.insert(0, (node.right, tmp_sum-node.val))
queue.insert(0, (node.left, tmp_sum-node.val))
return False

方法四:后序遍历 + 栈

直接将路径保存在栈中,每次进入不同的层不需要记录当前的和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution:
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
pre, cur = None, root
tmp_sum = 0
stack = []
while cur or len(stack) > 0:
while cur:
stack.append(cur)
tmp_sum += cur.val
cur = cur.left # 最左子树
cur = stack[-1]
if not cur.left and not cur.right and tmp_sum == sum:
return True
if cur.right and pre != cur.right:
cur = cur.right # 右子树
else:
pre = cur
stack.pop() # 左子树
tmp_sum -= cur.val
cur = None
return False

113. 路径总和 II

给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。

说明: 叶子节点是指没有子节点的节点。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
给定如下二叉树,以及目标和 sum = 22,

5
/
4 8
/ /
11 13 4
/ /
7 2 5 1
返回:

[
[5,4,11,2],
[5,8,4,5]
]

方法:回溯

注意path传参,要写成path[:]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
res = []
self.dfs(root,sum,res,[])
return res
def dfs(self, root, target, res, path):
if not root:return
path += [root.val]
if sum(path) == target and not root.left and not root.right:
res.append(path)
return
if root.left:
self.dfs(root.left,target,res,path[:])
if root.right:
self.dfs(root.right,target,res,path[:])
path.pop(-1) # 回溯

124. 二叉树中的最大路径和

给定一个非空二叉树,返回其最大路径和。

本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。

示例 1:

1
2
3
4
5
6
7
输入: [1,2,3]

1
/
2 3

输出: 6

示例 2:

1
2
3
4
5
6
7
8
9
输入: [-10,9,20,null,null,15,7]

  -10
   /
  9  20
    /  
   15   7

输出: 42

大专栏  python解leetcode二叉树(2)re>

方法:递归

一条路径必定有一个节点最接近根节点,而该条路径的和就是这个节点的值加上它左右路径的和。我们现在要求最大路径和,那么就要分别得到左右两条路径的最大和。

而左路径的最大和为左节点的值加上它左右路径中较大的路径和,右路径最大和为右节点的值加上它左右路径中较大的路径和。

注意如果某条子路径的和为负,应该将该条子路径直接砍掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def maxPathSum(self, root: TreeNode) -> int:
self.maxSum = float('-inf')
self._maxPathSum(root)
return self.maxSum

def _maxPathSum(self,root):
if root is None: return 0
left = self._maxPathSum(root.left)
right = self._maxPathSum(root.right)
if left<0: left = 0
if right<0: right = 0
self.maxSum = max(self.maxSum, root.val + left + right)
return max(left, right) + root.val

437. 路径总和 III

给定一个二叉树,它的每个结点都存放着一个整数值。

找出路径和等于给定数值的路径总数。

路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8

10
/
5 -3
/
3 2 11
/
3 -2 1

返回 3。和等于 8 的路径有:

1. 5 -> 3
2. 5 -> 2 -> 1
3. -3 -> 11

方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> int:
if not root:return 0
return self.dfs(root, sum) + self.pathSum(root.left, sum) + self.pathSum(root.right, sum)

def dfs(self, root, sum):
res = 0
if not root:return res
sum -= root.val
if sum == 0:
res += 1
res += self.dfs(root.left, sum)
res += self.dfs(root.right, sum)
return res

129. 求根到叶子节点数字之和

给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。

例如,从根到叶子节点路径 1->2->3 代表数字 123。

计算从根到叶子节点生成的所有数字之和。

说明: 叶子节点是指没有子节点的节点。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
输入: [4,9,0,5,1]
4
/
9 0
 /
5 1
输出: 1026
解释:
从根到叶子节点路径 4->9->5 代表数字 495.
从根到叶子节点路径 4->9->1 代表数字 491.
从根到叶子节点路径 4->0 代表数字 40.
因此,数字总和 = 495 + 491 + 40 = 1026.

方法

和257题求所有路径是一样的。

res = 0当做参数传给函数,那么函数最后的结果不会影响到res,但是如果把res = [0]即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
def sumNumbers(self, root: TreeNode) -> int:
if not root:return 0
res = [0]
self.dfs(root, res, root.val)
return res[0]
def dfs(self,root, res, path):
if not root.left and not root.right:
res[0] += path
if root.left:
self.dfs(root.left, res, path*10+root.left.val)
if root.right:
self.dfs(root.right, res, path*10+root.right.val)

257. 二叉树的所有路径

给定一个二叉树,返回所有从根节点到叶子节点的路径。

说明: 叶子节点是指没有子节点的节点。

示例:

1
2
3
4
5
6
7
8
9
10
输入:

1
/
2 3

5

输出: ["1->2->5", "1->3"]
解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3

方法

把path作为字符串,res作为数组保存字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
def binaryTreePaths(self, root: TreeNode) -> List[str]:
if not root:return []
res = []
self.dfs(root, res, ''+str(root.val))
return res
def dfs(self, root, res, path):
if not root.left and not root.right:
res.append(path)
if root.left:
self.dfs(root.left, res, path+'->'+str(root.left.val))
if root.right:
self.dfs(root.right, res, path+'->'+str(root.right.val))

543. 二叉树的直径

给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过根结点。

示例 :

1
2
3
4
5
6
7
8
给定二叉树

1
/
2 3
/
4 5
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。

注意:两结点之间的路径长度是以它们之间边的数目表示。

方法:递归

看叶子节点的左右子树的深度都是0,那么,它的深度是0,一个数的深度是其左右子树的最大值+1。

树总的最大宽度是其左右子树高度的和中的最大值。

求最大距离的过程需要在递归里面写,所以这个步骤比较巧妙,一个递归实现了两个作用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution:
def diameterOfBinaryTree(self, root: TreeNode) -> int:
if not root:
return 0
self.diameter = 0
self.getDepth(root)
return self.diameter

def getDepth(self, root):
if not root:
return 0
left = self.getDepth(root.left)
right = self.getDepth(root.right)
self.diameter = max(self.diameter, left+right)
return 1 + max(left, right)

687. 最长同值路径

给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。

注意:两个节点之间的路径长度由它们之间的边数表示。

示例 1:

1
2
3
4
5
6
7
8
输入:

5
/
4 5
/
1 1 5
输出:2

示例 2:

1
2
3
4
5
6
7
8
输入:

1
/
4 5
/
4 4 5
输出:2

注意: 给定的二叉树不超过10000个结点。 树的高度不超过1000。

方法:递归 + dfs

求一个顶点到所有根节点的路径,时刻保留相等元素的最大值。相等元素的最大值是左右子树的相等元素的最大值+1,所以是递归。

定义的DFS函数是获得在通过root节点的情况下,最长单臂路径。其中更新的res是左右臂都算上的。所以这个题和普通的题是有点不一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
def longestUnivaluePath(self, root: TreeNode) -> int:
longest = [0]
def dfs(root):
if not root:
return 0
left_len, right_len = dfs(root.left), dfs(root.right)
left = left_len + 1 if root.left and root.left.val == root.val else 0
right = right_len + 1 if root.right and root.right.val == root.val else 0
longest[0] = max(longest[0], left + right)
return max(left, right)
dfs(root)
return longest[0]

783. 二叉搜索树结点最小距离

该题和530. 二叉搜索树的最小绝对差 一样。可以用相同方法解题。

给定一个二叉搜索树的根结点 root, 返回树中任意两节点的差的最小值。

示例:

1
2
3
输入: root = [4,2,6,1,3,null,null]
输出: 1
解释: 注意,root是树结点对象(TreeNode object),而不是数组。

给定的树 [4,2,6,1,3,null,null] 可表示为下图:

1
2
3
4
5
      4
/
2 6
/
1 3

最小的差值是 1, 它是节点1和节点2的差值, 也是节点3和节点2的差值。

注意:

二叉树的大小范围在 2 到 100。

二叉树总是有效的,每个节点的值都是整数,且不重复。

方法:中序遍历+递归

中序遍历,得到有序列表,然后找出相邻的两个节点差值的最小值

1
2
3
4
5
6
7
8
9
10
11
class Solution:
def minDiffInBST(self, root: TreeNode) -> int:
vals = []
def inOrder(root):
if not root:
return
inOrder(root.left)
vals.append(root.val)
inOrder(root.right)
inOrder(root)
return min([vals[i+1]-vals[i] for i in range(len(vals)-1)])

938. 二叉搜索树的范围和

给定二叉搜索树的根结点 root,返回 L 和 R(含)之间的所有结点的值的和。

二叉搜索树保证具有唯一的值。

示例 1:

1
2
输入:root = [10,5,15,3,7,null,18], L = 7, R = 15
输出:32

示例 2:

1
2
输入:root = [10,5,15,3,7,13,18,1,null,6], L = 6, R = 10
输出:23

提示:树中的结点数量最多为 10000 个。最终的答案保证小于 2^31。

方法:BST+递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def rangeSumBST(self, root: TreeNode, L: int, R: int) -> int:
if not root:
return 0
res = 0
if L <= root.val <= R:
res += root.val
res += self.rangeSumBST(root.left, L, R)
res += self.rangeSumBST(root.right, L, R)
elif root.val < L:
res += self.rangeSumBST(root.right, L, R)
elif root.val > R:
res += self.rangeSumBST(root.left, L, R)
return res

参考

猜你喜欢

转载自www.cnblogs.com/dajunjun/p/11699238.html
今日推荐