代码随想录算法训练营第十四天 | 110.平衡二叉树、257.二叉树的所有路径、404.左叶子之和
文章目录
- 代码随想录算法训练营第十四天 | 110.平衡二叉树、257.二叉树的所有路径、404.左叶子之和
- 1 LeetCode 110.平衡二叉树
- 2 LeetCode 257.二叉树的所有路径
- 3 LeetCode 404.左叶子之和
1 LeetCode 110.平衡二叉树
题目链接:https://leetcode.cn/problems/balanced-binary-tree/
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
示例 1:
输入:root = [3,9,20,null,null,15,7] 输出:true
示例 2:
输入:root = [1,2,2,3,3,null,null,4,4] 输出:false
示例 3:
输入:root = [] 输出:true
提示:
- 树中的节点数在范围
[0, 5000]
内-104 <= Node.val <= 104
作为408选手,我想说本题也是408未来可能会涉及的题目,因此我们也必须注意一下,对于平衡二叉树的定义想必大家并不陌生(对于一棵二叉树,如果任何一个节点的左子树和右子树高度之差的绝对值不超过1,则这是一棵平衡二叉树,并且规定空平衡二叉树的高度为0,且空二叉树也是平衡的),知道平衡二叉树的定义之后,我们就很清楚我们需要分别求出节点的左子树和右子树的高度,然后求其差的绝对值是否超过1来判断,如果满足,则返回给上一层节点,以此类推,如果不满足就可以直接返回不是平衡二叉树,很明显我们需要使用后序遍历的方法来解决这道题目。
(1)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
class Solution:
def isBalanced(self, root: Optional[TreeNode]) -> bool:
def checkBalance(node):
if not node: # 空平衡二叉树
return 0
left_height = checkBalance(node.left) # 左子树高度
right_height = checkBalance(node.right) # 右子树高度
if left_height == -1 or right_height == -1 or abs(left_height - right_height) > 1: # 不符合平衡二叉树定义
return -1 # -1 代表不平衡
return max(left_height, right_height) + 1 # 返回最大高度
return checkBalance(root) != -1
checkBalance
函数用于递归地检查每个节点,如果遇到任何不平衡的子树,它会立即返回-1
,这样一旦发现不平衡,递归就会提前终止,并通过连锁反应快速传递不平衡的状态回到根节点,如果树是平衡的,checkBalance
会返回树的实际高度,而不是-1
,因此最终的isBalanced
调用检查checkBalance(root)
的返回值是否不等于-1
来确定整棵树是否平衡。
(2)C++版本代码
#include <iostream>
#include <algorithm>
class TreeNode {
public:
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class Solution {
public:
bool isBalanced(TreeNode* root) {
return checkBalance(root) != -1;
}
private:
int checkBalance(TreeNode* node) {
if (!node) { // 空树是平衡的
return 0;
}
int leftHeight = checkBalance(node->left);
if (leftHeight == -1) { // 左子树不平衡
return -1;
}
int rightHeight = checkBalance(node->right);
if (rightHeight == -1) { // 右子树不平衡
return -1;
}
if (abs(leftHeight - rightHeight) > 1) { // 当前节点不平衡
return -1;
}
return std::max(leftHeight, rightHeight) + 1; // 返回当前节点为根的树的高度
}
};
2 LeetCode 257.二叉树的所有路径
题目链接:https://www.heywhale.com/home/activity/recent
给你一个二叉树的根节点
root
,按 任意顺序 ,返回所有从根节点到叶子节点的路径。叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [1,2,3,null,5] 输出:["1->2->5","1->3"]
示例 2:
输入:root = [1] 输出:["1"]
提示:
- 树中节点的数目在范围
[1, 100]
内-100 <= Node.val <= 100
本题需要涉及收集递归过程中的路径,因此会涉及到回溯,我们从根节点开始,每次遍历到一个节点时,都会检查该节点是否是叶子节点(即没有子节点),如果是叶子节点,就将从根节点到该叶子节点的路径添加到结果列表中,遍历过程中,通过字符串拼接的方式构建路径,递归的过程保证了能够访问到树的每一个节点,从而找出所有可能的路径。
(1)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
class Solution:
def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
result = [] # 用于存储所有路径的结果列表
if not root: # 如果根节点为空,则直接返回空的结果列表
return result
def dfs(node, path): # 定义深度优先搜索函数,node为当前访问的节点,path为从根节点到当前节点的路径
if not node.left and not node.right: # 如果当前节点是叶子节点,将路径添加到结果列表中
result.append(path)
if node.left: # 如果存在左子节点,递归调用dfs函数,路径加上"->"和左子节点的值
dfs(node.left, path + "->" + str(node.left.val))
if node.right: # 如果存在右子节点,递归调用dfs函数,路径加上"->"和右子节点的值
dfs(node.right, path + "->" + str(node.right.val))
dfs(root, str(root.val)) # 从根节点开始递归搜索,初始路径为根节点的值
return result # 返回所有从根节点到叶子节点的路径
(2)C++版本代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
#include <vector>
#include <string>
using namespace std;
class Solution {
public:
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> result; // 用于存储所有路径的结果列表
if (!root) return result; // 如果根节点为空,则直接返回空的结果列表
// 定义深度优先搜索函数,node为当前访问的节点,path为从根节点到当前节点的路径
auto dfs = [&](TreeNode* node, string path) {
if (!node->left && !node->right) { // 如果当前节点是叶子节点,将路径添加到结果列表中
result.push_back(path);
}
if (node->left) { // 如果存在左子节点,递归调用dfs函数,路径加上"->"和左子节点的值
dfs(node->left, path + "->" + to_string(node->left->val));
}
if (node->right) { // 如果存在右子节点,递归调用dfs函数,路径加上"->"和右子节点的值
dfs(node->right, path + "->" + to_string(node->right->val));
}
};
dfs(root, to_string(root->val)); // 从根节点开始递归搜索,初始路径为根节点的值
return result; // 返回所有从根节点到叶子节点的路径
}
};
3 LeetCode 404.左叶子之和
题目链接:https://leetcode.cn/problems/sum-of-left-leaves/description/
给定二叉树的根节点
root
,返回所有左叶子之和。示例 1:
输入: root = [3,9,20,null,null,15,7] 输出: 24 解释: 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24
示例 2:
输入: root = [1] 输出: 0
提示:
- 节点数在
[1, 1000]
范围内-1000 <= Node.val <= 1000
这道题目力扣上面是没有详细介绍什么是左叶子,但是根据题目我们也不难看出,左叶子的定义就是某节点的左孩子存在,且其左孩子为叶子节点,那么此节点的左孩子就是左叶子。
需要注意的是,我们不能从当前节点来判断它是不是左叶子,因为左叶子本身也是叶子节点,但不能保证他是其父节点的左孩子,因此我们就需要从其父节点进行判断,判断的依据也就当左孩子的定义,我们需要用后序遍历的来进行遍历判断。
接下来我们按照卡哥的递归三部曲开始分析。
- 确定递归函数的参数和返回值:这个很简单,我们只需要传入根节点,返回值就是数值和。
- 确定终止条件:如果遍历到空节点,那左叶子值一定为0,我们还需要注意的是,如果当前节点不为空,但是其左右孩子不存在,我们也需要返回左叶子值为0.
- 确定单层递归的逻辑:那就是按照左叶子的定义写即可,那就是当遍历到左叶子时就记数,然后不断递归求左子树的左叶子之和和右子树左叶子之和,最后相加。
现在我们开始写代码复现我们的思路来证明它是正确的。
(1)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
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
if not root or (not root.left and not root.right):
return 0
leftNums = self.sumOfLeftLeaves(root.left)
if root.left and not root.left.left and not root.left.right:
leftNums += root.left.val
rightNums = self.sumOfLeftLeaves(root.right)
return leftNums + rightNums
(2)C++版本代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
if (!root || (!root->left && !root->right)) {
return 0;
}
int leftNums = sumOfLeftLeaves(root->left);
if (root->left && !root->left->left && !root->left->right) {
leftNums += root->left->val;
}
int rightNums = sumOfLeftLeaves(root->right);
return leftNums + rightNums;
}
};