今日题目
题目 | 难度 | 备注 |
---|---|---|
404. 左叶子之和 | 简单 | |
513. 找树左下角的值 | 简单 | |
112. 路径总和 | 简单 | |
106. 从中序与后序遍历序列构造二叉树 | 中等 | |
654. 最大二叉树 | 中等 |
树篇 Ⅲ
题目:404. 左叶子之和
一、源代码
class Solution {
private:
int sum = 0;
void DFS(TreeNode* root) {
if (!root) return;
if (root->left && !root->left->left && !root->left->right) { // 左子树为叶子结点
sum += root->left->val;
}
DFS(root->left);
DFS(root->right);
}
public:
int sumOfLeftLeaves(TreeNode* root) {
DFS(root);
return sum;
}
};
二、代码思路
DFS 遍历树,遇到左子树为叶子结点的,则将它左子树的值加入到 sum 中。
题目:513. 找树左下角的值
一、源代码
class Solution {
private:
int mostDeepHight = -1,mostDeepVal = -1;
void DFS(TreeNode* root, int h) {
if (!root) return;
if (!root->left && !root->right) { // 遇到叶子结点进行判断
if (h > mostDeepHight) { // 当前结点深度更深,则更新。由于左结点优先,所以记录的为最左侧结点的值
mostDeepHight = h;
mostDeepVal = root->val;
}
}
DFS(root->left, h + 1); // 先访问左子树,保证左结点优先
DFS(root->right, h + 1);
}
public:
int findBottomLeftValue(TreeNode* root) {
DFS(root,0);
return mostDeepVal;
}
};
二、代码思路
先序遍历树,利用 mostDeepHight 记录遍历过程中遇到的最大深度,mostDeepVal 记录遍历过程中遇到的最大深度的结点值。遍历时遇到叶子结点则进行判断,若该叶子结点的深度大于mostDeepHight 则更新 mostDeepHight 和mostDeepVal 。这样可得到最底层的结点。
而利用先序遍历,先访问当前结点的左子树,再访问右子树,再加上 叶子结点的深度大于mostDeepHight 才更新(并非大于等于)这样就保证了对同一层结点,只记录最左边的结点值,即为答案。
题目:112. 路径总和
一、源代码
class Solution {
private:
bool hasSum = false; // 标志符号,存在则置为 true
void DFS(TreeNode* root, int sum, int targetSum) {
if (!root) return;
sum += root->val; // 记录结点值之和
if (!root->left && !root->right) { // 遇到叶子结点时进行判断
if (sum == targetSum) {
hasSum = true;
return;
}
}
DFS(root->left,sum,targetSum);
DFS(root->right,sum,targetSum);
}
public:
bool hasPathSum(TreeNode* root, int targetSum) {
DFS(root,0,targetSum);
return hasSum;
}
};
二、代码思路
DFS 遍历树同时记录路径的结点值之和(sum),若访问叶子结点时遇到 sum == targetSum,则把 hasSum 置为 true (初始化为false),最后返回 hasSum 即可。
题目:106. 从中序与后序遍历序列构造二叉树
106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)
一、源代码
class Solution {
// 利用中序和后序序列性质,不断拆分 inorder 和 postorder 序列,每次选取一个要操作的序列,递归构造树
// l1 为指向当前要操作的中序序列的最左端,r1 为最右端
TreeNode* build(vector<int>& inorder, vector<int>& postorder, int l1,int r1,int l2, int r2) {
if (l1 > r1) return nullptr; // 当左指针l1 > 右指针r1,说明非法,构造的结点为空,所以返回 nullptr
TreeNode* root = new TreeNode; // 一次构造一个结点
root->val = postorder[r2]; // 结点的值为要操作的postorder 序列的最右一个
int i = l1;
for(;inorder[i] != root->val;i++); // 找到 postorder[r2] 在 inorder 中的下标
int llen = i - l1; // 左子树长度,即下一次要操作左序列长度
int rlen = r1 - i; // 右子树长度,即下一次要操作右序列长度
// 拆分 inorder,postorder,构造 root 的左右孩子
root->left = build(inorder, postorder, l1, l1 + llen - 1, l2, l2 + llen -1);
root->right = build(inorder,postorder,r1 - rlen + 1 , r1, r2 - rlen, r2 - 1);
return root;
}
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
TreeNode* root = build(inorder, postorder, 0, inorder.size() - 1, 0, postorder.size() - 1);
return root;
}
};
二、代码思路
利用中序和后序序列性质,不断拆分 inorder 和 postorder 序列,每次选取一个要操作的序列,递归构造树。
① 后序序列的最右侧的元素(假设为x),为树或子树的顶点。
② 中序序列以 x 为中心,x 左侧的元素为 x 的左子树, x 右侧的元素为 x 的右子树。
题目:654. 最大二叉树
一、源代码
class Solution {
private:
// 递归构建树,一次build 一个结点
TreeNode* build(vector<int>& nums, int l, int r) {
if (l > r) return nullptr; // 非法则 返回空结点
TreeNode* root = new TreeNode;
int maxIndx = -1, maxVal = -1;
for (int i = l; i <= r; i++) { // 找到最大值
if (nums[i] > maxVal) {
maxIndx = i;
maxVal = nums[i];
}
}
root->val = maxVal; // 用最大值构建结点 和左右孩子
root->left = build(nums, l, maxIndx - 1);
root->right = build(nums, maxIndx + 1, r);
return root;
}
public:
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
return build(nums, 0, nums.size() - 1);
}
};
二、代码思路
递归构建树,一次 build 一个结点,利用左右指针(l,r)不断拆分数组。每次只处理 l … … . r 之间的序列,从中选取最大值构建结点,并更新左右指针,构建左右子树。