Leecode 513. 找树左下角的值

题目描述

给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。

假设二叉树中至少有一个节点。

  • 示例 1:



输入: root = [2,1,3]

输出: 1

  • 示例 2:



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

输出: 7

迭代法

本题要求最后一层的最左侧节点,那么非常适合采用层序遍历的范式,到最后一层的第一个节点就是要找的数。但由于从上往下层序遍历的时候,并不知道当前层是否是最后一层,因此我们考虑使用一个vector来记录每一层的第一个节点。在遍历结束之后,再从这个vector中取出最后一个数,即为我们要找的最后一层的第一个节点。因此可以有代码如下:

class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
if(!root) return 0;
queue<TreeNode*> nodeQue;
nodeQue.push(root);
vector<int> firstVal; // 用于存放每一层最左侧的值
while(!nodeQue.empty()){
int size = nodeQue.size();
firstVal.push_back(nodeQue.front()->val); // 将当前层第一个节点的值放入firstVal中
for(int i = 0; i < size; i++){
TreeNode* cur = nodeQue.front();
nodeQue.pop();
if(cur->left) nodeQue.push(cur->left);
if(cur->right) nodeQue.push(cur->right);
}
}
return firstVal[firstVal.size()-1]; // 最后返回最后一层的第一个节点的值
}
};

对于层序遍历的标准模板应该都很熟悉了,本题的时间复杂度同样也是\(O(n)\)(即每个节点遍历一次),空间复杂度为\(O(\log n)\)(额外的一个vector大小与二叉树深度相等)。

Leecode 112. 路径总和

题目描述

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false

叶子节点 是指没有子节点的节点。

  • 示例 1:



输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22

输出:true

解释:等于目标和的根节点到叶节点路径如上图所示。

  • 示例 2:



输入:root = [1,2,3], targetSum = 5

输出:false

解释:树中存在两条根节点到叶子节点的路径:

(1 --> 2): 和为 3

(1 --> 3): 和为 4

不存在 sum = 5 的根节点到叶子节点的路径。

  • 示例 3:

输入:root = [], targetSum = 0

输出:false

解释:由于树是空的,所以不存在根节点到叶子节点的路径。

回溯法递归

本题和之前那道求所有路径的题目非常相似,同样也是只要将到达每个节点所经历的路径都记录下来,如果走到叶节点,则将当前路径和进行存放,最后再遍历检查一遍存放的路径和中是否存在有等于目标值的情况,如果有则返回true,否则返回false。根据这个思路可以得到如下代码:

class Solution {
public:
void pathSumHelper(TreeNode* curNode, vector<int>& pathSum, vector<TreeNode*> ndVec){ // 参数表示:当前节点、存放所有路径和的vec、存放到达当前节点的路径
if(!curNode) return; // 如果当前节点为空,则直接返回
ndVec.push_back(curNode); // 否则将当前节点纳入路径中
if(!curNode->left && !curNode->right){ // 如果当前节点为叶节点,则计算路径和,并存放
int curSum = 0; // 初始化路径和
for(int i = 0; i < ndVec.size(); i++){ // for循环遍历路径,求路径和
curSum += ndVec[i]->val;
}
pathSum.push_back(curSum); // 将路径和进行存放
}
if(curNode->left) pathSumHelper(curNode->left, pathSum, ndVec); // 递归回溯左子节点,回溯体现在其中的值传递
if(curNode->right) pathSumHelper(curNode->right, pathSum, ndVec); // 递归回溯右子节点
return;
} bool hasPathSum(TreeNode* root, int targetSum) {
vector<int> pathSum; // 用于存放所有路径和的vec
vector<TreeNode*> ndVec; // 用于存放当前路径中经过的所有节点
pathSumHelper(root, pathSum, ndVec); // 递归调用赋值函数,将所有路径和存放在pathSum中
for(int i = 0; i < pathSum.size(); i++){ // 遍历pathSum,检查是否有和目标值相等的值
if(targetSum == pathSum[i]) return true; //
}
return false;
}
};

同样也可以直接传入一个布尔变量和原本的目标值,在计算完路径和后直接进行比较并修改布尔遍历。这样不必使用一个vector来存放路径和,一定程度上降低空间复杂度:

class Solution {
public:
void pathSumHelper(TreeNode* curNode, vector<TreeNode*> ndVec, bool& result, int targetSum){ // 传入布尔变量和目标值
if(result || !curNode) return; // 如果已经找到,或者当前节点为空,都要返回
ndVec.push_back(curNode);
if(!curNode->left && !curNode->right){
int curSum = 0;
for(int i = 0; i < ndVec.size(); i++){
curSum += ndVec[i]->val;
}
if(curSum == targetSum){ // 计算完路径和后直接与目标值比较,如果相等的话就将result变为true并返回
result = true;
return;
}
}
if(curNode->left) pathSumHelper(curNode->left, ndVec, result, targetSum);
if(curNode->right) pathSumHelper(curNode->right, ndVec, result, targetSum);
return;
} bool hasPathSum(TreeNode* root, int targetSum) {
vector<int> pathSum;
vector<TreeNode*> ndVec;
bool result = false; // 初始没有找到,设置为false
pathSumHelper(root, ndVec, result, targetSum); // 递归调用
return result;
}
};

Leecode 113. 路径总和 II

题目描述

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

叶子节点 是指没有子节点的节点。

  • 示例 1:



输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22

输出:[[5,4,11,2],[5,8,4,5]]

  • 示例 2:



输入:root = [1,2,3], targetSum = 5

输出:[]

  • 示例 3:

输入:root = [1,2], targetSum = 0

输出:[]

回溯递归

和上一题非常类似的方法,区别仅在于需要用一个vector来存放路径。

class Solution {
public:
void pathSumHelper(TreeNode* curNode, vector<vector<int>>& result, vector<TreeNode*> ndVec, int targetSum){
if(!curNode) return;
ndVec.push_back(curNode);
if(!curNode->left && !curNode->right) {
vector<int> path;
int sum = 0;
for(int i = 0; i < ndVec.size(); i++){
sum += ndVec[i]->val;
path.push_back(ndVec[i]->val);
}
if(sum == targetSum)result.push_back(path);
}
if(curNode->left) pathSumHelper(curNode->left, result, ndVec, targetSum);
if(curNode->right) pathSumHelper(curNode->right, result, ndVec, targetSum);
return;
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
vector<vector<int>> result;
vector<TreeNode*> ndVec;
pathSumHelper(root, result, ndVec, targetSum);
return result;
}
};

Leecode 106. 从中序与后序遍历序列构造二叉树

题目描述

给定两个整数数组 inorderpostorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树

  • 示例 1:



输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]

输出:[3,9,20,null,null,15,7]

  • 示例 2:

输入:inorder = [-1], postorder = [-1]

输出:[-1]

解题思路与代码展示

本题从思路上不难理解,后序遍历的最后一个数表示了当前树中的根节点,根据根节点中的值将前序序列分成两半,可以得到左右两个子树的前序序列。同时根据分割后的前序序列长度也可以将后序序列以同样的长度进行分割,得到左右子树的后序序列。从而再进行递归,即可得到整颗树的结构。故我们可以写出以下代码:

class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if(inorder.empty() || postorder.empty()) return nullptr; // 处理递归终止条件,如果当前序列为空,则返回空
int rootVal = postorder[postorder.size()-1]; // 后序序列的最后一个值即为根节点中的值
TreeNode* root = new TreeNode(rootVal); // 新建根节点 int cutPoint = find(inorder.begin(), inorder.end(), rootVal) - inorder.begin(); // 查找根节点在前序序列中的位置
vector<int> leftInorder(inorder.begin(), inorder.begin()+cutPoint); // 构造左子树的前序序列
vector<int> leftPostorder(postorder.begin(), postorder.begin()+cutPoint); // 构造左子树的后序序列 vector<int> rightInorder(inorder.begin() + cutPoint + 1, inorder.end()); // 构造右子树的前序序列
vector<int> rightPostorder(postorder.begin() + cutPoint, postorder.end()-1); // 构造右子树的后续序列 root->left = buildTree(leftInorder, leftPostorder); // 对左子树进行递归
root->right = buildTree(rightInorder, rightPostorder); // 对右子树进行递归 return root;
}
};

上面代码对两个vector进行递归即可建立整个二叉树。同时这部分有几道非常类似的题目,都是根据遍历结果构建二叉树,下面只贴出链接和相应代码,并不过多赘述。

class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.empty() || inorder.empty()) return nullptr;
TreeNode* root = new TreeNode(preorder[0]);
int cutPoint = find(inorder.begin(), inorder.end(), root->val) - inorder.begin();
vector<int> leftPre(preorder.begin()+1, preorder.begin()+cutPoint+1);
vector<int> leftIn(inorder.begin(), inorder.begin()+cutPoint); vector<int> rightPre(preorder.begin()+cutPoint+1, preorder.end());
vector<int> rightIn(inorder.begin()+cutPoint+1, inorder.end()); root->left = buildTree(leftPre, leftIn);
root->right = buildTree(rightPre, rightIn); return root;
}
};
class Solution {
public:
TreeNode* constructFromPrePost(vector<int>& preorder, vector<int>& postorder) {
if (preorder.empty()) return nullptr; TreeNode* root = new TreeNode(preorder[0]);
if (preorder.size() == 1) return root; int L = 0;
// 查找前序第二个元素(左子树根)在后序中的位置
for (int i = 0; i < postorder.size(); ++i) {
if (postorder[i] == preorder[1]) {
L = i + 1; // 左子树节点数 = 位置索引 + 1
break;
}
} // 分割左子树数组
vector<int> leftPre(preorder.begin() + 1, preorder.begin() + 1 + L);
vector<int> leftPost(postorder.begin(), postorder.begin() + L); // 分割右子树数组(修正结束位置)
vector<int> rightPre(preorder.begin() + 1 + L, preorder.end());
vector<int> rightPost(postorder.begin() + L, postorder.end() - 1); // 递归构建
root->left = constructFromPrePost(leftPre, leftPost);
root->right = constructFromPrePost(rightPre, rightPost); return root;
}
};

今日总结

今天题目都还挺简单,最难的其实是最后刷了一道用前序+后序建立二叉树,在没有中序的情况下可能有多个解,但也需要能够想到怎么才能分割出满足条件的解,

今天力扣到60题了,再接再厉!

代码随想录第十六天 | Leecode 513. 找树左下角的值、112. 路径总和、113. 路径总和 II、106. 从中序与后序遍历序列构造二叉树的更多相关文章

  1. 代码随想录算法训练营day18 | leetcode 513.找树左下角的值 ● 112. 路径总和 113.路径总和ii ● 106.从中序与后序遍历序列构造二叉树

    LeetCode 513.找树左下角的值 分析1.0 二叉树的 最底层 最左边 节点的值,层序遍历获取最后一层首个节点值,记录每一层的首个节点,当没有下一层时,返回这个节点 class Solutio ...

  2. Leetcode之深度优先搜索(DFS)专题-513. 找树左下角的值(Find Bottom Left Tree Value)

    Leetcode之深度优先搜索(DFS)专题-513. 找树左下角的值(Find Bottom Left Tree Value) 深度优先搜索的解题详细介绍,点击 给定一个二叉树,在树的最后一行找到最 ...

  3. LeetCode 513. 找树左下角的值(Find Bottom Left Tree Value)

    513. 找树左下角的值 513. Find Bottom Left Tree Value 题目描述 给定一个二叉树,在树的最后一行找到最左边的值. LeetCode513. Find Bottom ...

  4. Java实现 LeetCode 513 找树左下角的值

    513. 找树左下角的值 给定一个二叉树,在树的最后一行找到最左边的值. 示例 1: 输入: 2 / \ 1 3 输出: 1 示例 2: 输入: 1 / \ 2 3 / / \ 4 5 6 / 7 输 ...

  5. 513 Find Bottom Left Tree Value 找树左下角的值

    给定一个二叉树,在树的最后一行找到最左边的值. 详见:https://leetcode.com/problems/find-bottom-left-tree-value/description/ C+ ...

  6. 领扣(LeetCode)找树左下角的值 个人题解

    给定一个二叉树,在树的最后一行找到最左边的值. 示例 1: 输入: 2 / \ 1 3 输出: 1 示例 2: 输入: 1 / \ 2 3 / / \ 4 5 6 / 7 输出: 7 注意: 您可以假 ...

  7. [Swift]LeetCode513. 找树左下角的值 | Find Bottom Left Tree Value

    Given a binary tree, find the leftmost value in the last row of the tree. Example 1: Input: 2 / \ 1 ...

  8. Leetcode513. Find Bottom Left Tree Value找树左下角的值

    给定一个二叉树,在树的最后一行找到最左边的值. 示例 1: 输入: 2 / \ 1 3 输出: 1 示例 2: 输入: 1 / \ 2 3 / / \ 4 5 6 / 7 输出: 7 注意: 您可以假 ...

  9. javaSE第十六天

    第十六天    140 1:List的子类(掌握)    140 (1)List的子类特点    140 (2)ArrayList    141 A:没有特有功能需要学习    141 B:案例    ...

  10. HihoCoder第十周:后序遍历

    也就在大二学数据结构的时候知道了树的前序遍历.后序遍历.中序遍历.之后就忘了,在之后就是大四研究生老师考我,我当时还不知道,真够丢人的.自此之后,知道了如何通过其中两个得到第三个,但是也没有编程实现过 ...

随机推荐

  1. Flink同步kafka到iceberg(cos存储)

    一.flink到logger 1.source create table source_table ( id bigint comment '唯一编号' ,order_number bigint co ...

  2. flutter-使用flutter_app_upgrade进行版本更新要点

  3. Springboot 3.x 集成Knife4j [踩坑日记]

    之前项目用的是SpringBoot2.x 新项目用了SpringBoot3.x版本,引入Knife4j 报错java.lang.TypeNotPresentException: Type javax. ...

  4. 普通人如何靠 AI 副业,1 个月实现月薪 3 万 +

    在物价飞涨.经济低迷的今天,仅靠死工资,却有着不固定的开销?房贷.车贷.孩子的教育费用-- 望着日益增长的开销,你是否也在夜深人静时,为钱包的羞涩而发愁?无数次幻想过拥有一份高收入的副业,却始终在迷茫 ...

  5. Linux - 关于yum源 file & ftp & http 的三种配置方式

    一.环境准备 1.两台Centos服务器:node1.node2 2.配置ip:node1(192.168.2.111).node2(192.168.2.112) 3.关闭防火墙 systemctl ...

  6. 全网最强 DeepSeek 插件上线!支持多家云服务,一键解锁满血版 AI

    前言 自 DeepSeek 推出以来,其回答质量备受好评.然而,许多用户在连续提问时经常遇到"服务器繁忙,请稍后再试"的提示.随着各大云服务商陆续部署 DeepSeek 的完整模型 ...

  7. Python基础-模块和面向对象-shutil、re、bs4、requests模块

    概要: 模块 自定义模块(已经讲了) 内置模块 shutil re 正则表达式 第三方模块 requests 模块 bs4 模块 面向对象: 面向对象(Object-Oriented Programm ...

  8. [tldr] GO泛型编程

    最少的内容简述如何在GO中使用泛型编程 函数泛型 func f[T any](s Set[T]) { } 在函数声明的时候添加一个[]作为泛型的说明, 在使用的时候是可以自动推断 很多时候, any的 ...

  9. Nginx 配置 HTTPS 完整过程

    配置站点使用 https,并且将 http 重定向至 https. 1. nginx 的 ssl 模块安装 查看 nginx 是否安装 http_ssl_module 模块. $ /usr/local ...

  10. BUUCTF---Cipher1(playfair)

    playfair Playfair密码原理以及该题解题步骤 Playfair密码(Playfair cipher 或 Playfair square)一种替换密码,1854年由查尔斯·惠斯通(Char ...