题源:LeetCode 图源:VisuAlgo
这篇文章汇总了数据结构二叉树 (Binary Tree) 相关问题的多种解法。针对简单题目
![26ef81d5d7465c9120895570bba616b2.gif](https://img-blog.csdnimg.cn/img_convert/26ef81d5d7465c9120895570bba616b2.gif)
目录
1 / 二叉树的最大深度
2 / 平衡二叉树
3 / 二叉树中的最大路径和
1 / 二叉树的最大深度
-- 问题描述
给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7]。
3
/
9 20
/
15 7
输入:[3,9,20,null,null,15,7]
输出:3
Python题目提供信息:
# 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
-- 解法一
☔️ List + None元素标记不同层(子父节点)
List 是实现Tree的最近暗淡的数据结构,但容易导致新加入元素难辨处于何种位置。(比如,究竟是右节点呢,还是下一层的节点?)
因此,用List实现时,我们完全模拟输入列表信息,用None划分不同层级。
if cur_node: ... elif queue: ...
排除了达到队列尾端queue
为None的情况,确指「仅元素为None时」,即到达分层位置。
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root: return 0
# Use a None to mark a level (increase depth)
queue = [root, None]
depth = 1
while queue:
# Pop out the current node, and append its children
cur_node = queue.pop(0)
if cur_node:
if cur_node.left: queue.append(cur_node.left)
if cur_node.right: queue.append(cur_node.right)
elif queue:
# Mark a new level
queue.append(None)
depth += 1
return depth
-- 解法二
☔️ BFS广度优先搜索,使用双端队列 deque()
加入内层循环后,遍历同层节点以添加下一层节点,但不做depth
的增加。多了一层循环,但每个节点只访问了一次,时间复杂度还是
import collections
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root: return 0
queue = collections.deque()
queue.append(root)
depth = 0
while queue:
depth += 1
# Only iterate through nodes from the same level
for _ in range(len(queue)):
cur_node = queue.popleft()
if cur_node.left:
queue.append(cur_node.left)
if cur_node.right:
queue.append(cur_node.right)
return depth
-- 解法三
☔️ DFS深度优先搜索,使用递归
import collections
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root: return 0
self.depth = 0
self._depthFirstSearch(root, 0)
return self.depth
def _depthFirstSearch(self, node: TreeNode, level: int):
if not node: return
if self.depth < level + 1:
self.depth = level + 1
self._depthFirstSearch(node.left, level + 1)
self._depthFirstSearch(node.right, level + 1)
-- 解法四
☔️ DFS深度优先搜索 + 分治算法,使用递归
分治法 (Devide-and-Conquer) 的工作原理是将问题递归 分解为两个或多个相同或相关类型的子问题,直到这些子问题变得足够简单以至于可以直接解决。然后将子问题的解决方案组合起来,以解决原始问题。
利用分治法解决问题有下面三个步骤:
1. 分解:将原问题分解为多个子问题,每个子问题与原问题类型相同,但比原问题规模小。
2. 解决:递归求解子问题,如果子问题规模足够小,直接可以求解。
3. 合并:合并子问题的解,得到原问题的解。
—— 黄哥Python:分治算法
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root: return 0
return 1 + max(self.maxDepth(root.left),
self.maxDepth(root.right))
2 / 平衡二叉树
-- 问题描述
给定一个二叉树,判断它是否是高度平衡的二叉树。
一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
示例:
![18fbe166b1a03db2078243aa05c9e3bf.png](https://img-blog.csdnimg.cn/img_convert/18fbe166b1a03db2078243aa05c9e3bf.png)
输入:root = [1,2,2,3,3,null,null,4,4]
输出:false
-- 解法一:递归
对于满足条件就返回某值的计数类问题,写递归时可能以为不满足条件返回False与int的数据类型冲突。此时,通常用-1标记不满足条件的情况。
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
if not root: return True
return self._countHight(root) >= 0
def _countHight(self, node: TreeNode) -> int:
if not node: return 0
lh = self._countHight(node.left)
rh = self._countHight(node.right)
if lh >= 0 and rh >= 0 and abs(lh - rh) <= 1:
return max(lh, rh) + 1
else:
return -1
3 / 二叉树中的最大路径和
-- 问题描述
给你一个二叉树的根节点 root ,返回其最大路径和。
本题中,路径被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。该路径 至少包含一个 节点,且不一定经过根节点。
示例 1:
![a01663b0b15f669480fe6a17e4e144f4.png](https://img-blog.csdnimg.cn/img_convert/a01663b0b15f669480fe6a17e4e144f4.png)
输入:root = [1,2,3]
输出:6
-- 解法一:递归
一个在最长路径上的节点只可能处于两种情况:
1. 位于最长路径的根节点,
(node.left
和 node.right
均在路径中)。
2. 位于最长路径上的某子节点,
(node
的父节点同样在路径中)。
- 第一种情况,可能构成最大路径的路径有:
- 当前节点(左右字数路径值均为负);
- 当前节点 + 左子树;
- 当前节点 + 右子树;
- 当前节点 + 左子树 + 右子树。
我们将上述四种最大情况的cur_max
与当前最长路径之作比较,并适时直接替换最长路径和self.maxSum
(无需迭代增值)。
- 第二种情况,可能构成最大路径的路径有:
- 当前节点(左右字数路径值均为负);
- 当前节点 + 左子树;
- 当前节点 + 右子树。
因为这种情况假设的是父节点一定位于最大路径,所以不能同时包含左右子树。
该最大和值需通过递归向父节点传递并叠加。
本题重点是明确节点可能处于的各种情况,分情况做实现。
class Solution:
def maxPathSum(self, root: TreeNode) -> int:
if not root: return 0
self.maxSum = -sys.maxsize - 1
self._findPath(root)
return self.maxSum
def _findPath(self, node: TreeNode) -> int:
if not node: return 0
lm = self._findPath(node.left)
rm = self._findPath(node.right)
cur_max = node.val + max(0, lm, rm, lm + rm)
self.maxSum = max(self.maxSum, cur_max)
return node.val + max(0, lm, rm)
![9ecd2d8c64d1869672aaae2b713e7346.gif](https://img-blog.csdnimg.cn/img_convert/9ecd2d8c64d1869672aaae2b713e7346.gif)