LeetCode题解 二叉树(八):404 左叶子之和;513 找树左下角的值;112 路径总和;113 路径总和II

news2024/11/14 3:57:41

二叉树

404 左叶子之和 easy

左叶子结点也好判断,若某结点属于左结点,且无子树,就是左叶子结点

即也如此,所以如果要判断,必然要从父结点下手,涉及到三层结点的处理

如果要使用递归法,要使用后序遍历(左右中),从下往上进行累加,代码如下:

int sumOfLeftLeaves(TreeNode* root) {
    if (!root) return 0;
    int leftValSum = 0;
    if (root->left && !root->left->left && !root->left->right)
        leftValSum += root->left->val;
    return leftValSum + sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right);

之所以看不出来后序遍历的痕迹,是因为左右中写在一起,做return的结果。

而迭代法,则前中后三种写法皆可,此处以前序遍历为例,代码如下:

int sumOfLeftLeaves(TreeNode* root) {
    stack<TreeNode*> stk;
    if (root) stk.push(root);
    int res = 0;

    while (!stk.empty()) {
        TreeNode* cur = stk.top();
        stk.pop();
        if (cur->left && !cur->left->left && !cur->left->right)
            res += cur->left->val;
        if (cur->left) stk.push(cur->left);
        if (cur->right) stk.push(cur->right);
    }

    return res;
}

利用这道题,顺道回顾一下前序遍历的统一写法,即标记法:

int sumOfLeftLeaves(TreeNode* root) {
    stack<TreeNode*> stk;
    int res = 0;
    if(!root) return res;
    stk.push(root);
    while (!stk.empty()) {
        TreeNode *cur = stk.top();
        if (cur) {
            stk.pop();
            if (cur->right) stk.push(cur->right);
            if (cur->left) {
                stk.push(cur->left);
                if (!cur->left->left && !cur->left->right)
                    res += cur->left->val;
            }
            stk.push(cur);
            stk.push(nullptr);
        }
        else {
            stk.pop();
            cur = stk.top();
            stk.pop();
        }
    }

    return res;
}

513 找树左下角的值 medium

树左下角,在这道题中的意思是最底层的最左边结点,因为示例2如下图所示:

513.找树左下角的值1

所以这道题用层序遍历,会极其方便,因为只需要记录最后一行的第一个结点即可,代码如下:

int findBottomLeftValue(TreeNode* root) {
    queue<TreeNode*> que;
    if (root) que.push(root);
    int res = 0;

    while (!que.empty()) {
        int size = que.size();
        for (int i = 0; i < size; i++) {
            TreeNode* cur = que.front();
            que.pop();
            if (i == 0) res = cur->val;
            if (cur->left) que.push(cur->left);
            if (cur->right) que.push(cur->right);
        }
    }

    return res;
}

这道题也可以用递归法求解,关键在于记录深度,以及如何记录下最后一行的最后一个结点,终止条件就自然是,先满足叶子结点,再判断深度是否为最大深度,如果是,就保存并退出。

int maxDepth = INT_MIN;
int res = 0;
void reversal (TreeNode* cur, int depth) {
    if (!cur->left && !cur->right) {
        if (depth > maxDepth) {
            maxDepth = depth;
            res = cur->val;
        }
        return;
    }
    if (cur->left) {
        reversal(cur->left, depth + 1);
    }
    if (cur->right) {
        reversal(cur->right, depth + 1);
    }
    return;
} 
int findBottomLeftValue(TreeNode* root) {
    reversal(root, 0);
    return res;
}

112 路径总和 easy

要判断是否存在一条根结点到叶子结点的路径之和,等于目标和

必然要用到深度遍历,且递归更加方便一些,要用到回溯的思想,

对于这道题,返回类型是布尔类型,传入参数必然有结点,路径之和,既然要与目标和比较,不如传入与目标值的差值,直至结果为0就自然等于目标和

终止条件自然是叶子结点与是否等于目标和()

bool reversal(TreeNode* cur, int sub) {
    if (!cur->left && !cur->right && sub == 0) return true;
    if (!cur->left && !cur->right) return false;
    if (cur->left) {
        sub -= cur->left->val;
        if (reversal(cur->left, sub)) return true;
        sub += cur->left->val;
    }
    if (cur->right) {
        sub -= cur->right->val;
        if (reversal(cur->right, sub)) return true;
        sub += cur->right->val;
    }
    return false;
}

bool hasPathSum(TreeNode* root, int targetSum) {
    if (!root) return false;
    return reversal(root, targetSum - root->val);
}

精简后的代码如下:

bool hasPathSum(TreeNode* root, int targetSum) {
    if (root == nullptr) return false;
    if (!root->left && !root->right && targetSum == root->val)
        return true;
    return hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, targetSum - root->val);
}

使用迭代法,栈里一个元素不仅要记录该节点指针,还要记录从头结点到该节点的路径数值总和

bool haspathsum(TreeNode* root, int sum) {
    if (root == null) return false;
    // 此时栈里要放的是pair<节点指针,路径数值>
    stack<pair<TreeNode*, int>> st;
    st.push(pair<TreeNode*, int>(root, root->val));
    while (!st.empty()) {
        pair<TreeNode*, int> node = st.top();
        st.pop();
        // 如果该节点是叶子节点了,同时该节点的路径数值等于sum,那么就返回true
        if (!node.first->left && !node.first->right && sum == node.second) return true;

        // 右节点,压进去一个节点的时候,将该节点的路径数值也记录下来
        if (node.first->right) {
            st.push(pair<TreeNode*, int>(node.first->right, node.second + node.first->right->val));
        }

        // 左节点,压进去一个节点的时候,将该节点的路径数值也记录下来
        if (node.first->left) {
            st.push(pair<TreeNode*, int>(node.first->left, node.second + node.first->left->val));
        }
    }
    return false;
}

113 路径总和II medium

这道题就不是找到一条了,而是找出所有,使用递归法也简单,只需要多添一个数组,记录路径上所遇结点值即可,另外也要对该数组进行回溯处理

vector<vector<int>> res;
vector<int> vec;

void recursive(TreeNode *cur, int count) {
    if (!cur->left && !cur->right && count == 0) {
        res.push_back(vec);
        return;
    }
    if (!cur->left && !cur->right) 
        return;

    if (cur->left) {
        vec.push_back(cur->left->val);
        count -= cur->left->val;
        recursive(cur->left, count);
        count += cur->left->val;
        vec.pop_back();
    }
    if (cur->right) {
        vec.push_back(cur->right->val);
        count -= cur->right->val;
        recursive(cur->right, count);
        count += cur->right->val;
        vec.pop_back();
    }
    return ;
}

vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
    if (!root) return res;
    vec.push_back(root->val);
    recursive(root, targetSum - root->val);

    return res;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/132097.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(二十三)大白话数据库服务器上的RAID存储架构的电池充放电原理

文章目录 1、RAID卡的缓存2、RAID卡的缓存里的数据会突然丢失怎么办?3、锂电池存在性能衰减问题1、RAID卡的缓存 服务器使用多块磁盘组成的RAID阵列的时候,一般会有一个RAID卡,这个RAID卡是带有一个缓存的,这个缓存不是直接用我们的服务器的主内存的那种模式,他是一种跟内…

网络静态路由综合实验

1.首先分配ip,配置ip和环回 [Huawei]sysname R1 [R1]interface LoopBack 0 [R1-LoopBack0]ip add 192.168.1.33 28 [R1-LoopBack0]q [R1]int l 1 [R1-LoopBack1]ip add 192.168.1.49 28 [R1-LoopBack1]q [R1]int g 0/0/0 [R1-GigabitEthernet0/0/0]ip add 192.168.1.1 30 [R1-…

JVM与Java体系结构

目录 前言 架构师每天都在思考什么&#xff1f; Java vs C Java生态圈 字节码 多语言混合编程 虚拟机与Java虚拟机 虚拟机 Java虚拟机 JVM的位置 JVM整体结构 Java代码执行流程 JVM的架构模型 举例 字节码反编译 总结 栈 JVM生命周期 虚拟机的启动 虚拟机的…

时间从来不语,确回答了所有问题——我的2022年终总结

趁着没阳&#xff0c;趁着电脑还能开机&#xff0c;趁着还能写&#xff0c;赶紧小结过去这一年。没有别的感觉&#xff0c;就是感觉太快&#xff0c;时间太过匆匆.....最大的感触是两个字“变化”&#xff0c;如果非要说四个字是“变化太快”&#xff0c;就如当下的yi情政策&am…

多线程_进阶

文章目录线程通信概念使用方式案例单例模式阻塞式队列线程池常见的锁策略乐观锁 悲观锁CASCAS存在的问题:ABA问题读写锁自旋锁公平锁 非公平锁非公平锁公平锁synchronizedjvm对synchronized的优化:锁升级synchronized的其他优化Lock体系synchronized vs lock独占锁vs共享锁独占…

Arch/Manjaro换源+安装常用的软件+安装显卡驱动

本文将教你&#xff1a;换源安装显卡驱动&#xff0c;安装常用软件例如腾讯会议&#xff0c;QQ&#xff0c;WPS 一起交流Linux知识&#xff0c;欢迎加入Skype群&#xff1a; Join conversationhttps://join.skype.com/q6wrF3d6Usni pacman换清华源 首先安装vim&#xff0c;用来…

(二十四)大白话RAID锂电池充放电导致的MySQL数据库性能抖动的优化

案例实战:RAID锂电池充放电导致的MySQL数据库性能抖动的优化 文章目录 1、磁盘故障怎么保障数据不丢失?2、线上MySQL数据库的性能定期抖动的原因1、磁盘故障怎么保障数据不丢失? 前面经过了几天的生产经验的一些铺垫,包括MySQL磁盘读写的机制,Linux存储系统的原理,RAID磁…

垃圾佬图拉丁装机

理论知识 缩线程 amd搞了个推土机架构 两个核心公用一个浮点运算单元&#xff0c;因为浮点运算只占百分之二十。 浮点运算应该交给更适合的gpu去做 好的对比 RDP 微软的RDP本身就定位是一个远程登录和维护windows系的工具&#xff0c;它为什么要支持管理别的系统&#xff…

【mybatis generator实战】 1.crud 2.计数 3.自定义复杂mapper代码组织

1.计数 2.CRUD 增 注意&#xff1a; insert&#xff1a;一个必须全部有值。 insertSelective是&#xff1a;部分有值就行&#xff0c;用的较多。 有疑问可以看源码&#xff0c;发现xxxSelective就是拼接了一些参数。 删 改 注意&#xff1a; 4个更新方法&#xff1a; …

QML学习笔记【06】:QML与C++交互

1 QML端直接调用C端变量及函数 1、 创建继承自QObject的C类&#xff0c;对象必须继承自QObject才能在QML被使用和访问 2、在类定义中使用Q_PROPERTY导出成员的READ、WRITE、NOTIFY接口&#xff0c;这样类中的成员变量就可以在QML调用和修改了&#xff0c;同时变量被修改后也会…

剑指 Offer 18. 删除链表的节点

一、题目描述 给定单向链表的头指针和一个要删除的节点的值&#xff0c;定义一个函数删除该节点。 返回删除后的链表的头节点。 示例 1: 输入: head [4,5,1,9], val 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点&#xff0c;那么在调用了你的函数之后&#xf…

2022年最后一篇推文 | C语言编程十诫

正文大家好&#xff0c;我是bug菌~2022年最后一篇推文原本选择一篇年终总结会比较合适&#xff0c;然而坐在窗台&#xff0c;望着窗外思索了良久&#xff0c;与往年总结有点不同&#xff0c;这个时间节点有着他的特殊性&#xff0c;不出意外&#xff0c;明年会有非常多的变化、…

OpenShift 4 - 用 HyperShift 实现以“托管集群”方式部署运行 OpenShift 集群

《OpenShift / RHEL / DevSecOps / Ansible 汇总目录》 说明&#xff1a;本文已经在 OpenShift 4.11 ACM 2.6 AWS 环境中验证 文章目录用 HyperShift 实现 OpenShift 托管集群什么是 HyperShift 托管集群以及架构HyperShift 托管集群的价值成本优势部署优势管理优势在 RHACM …

【Kaggle】Global Wheat Detection

代码链接 实验目的 小麦来自世界各地。密度的小麦植株经常重叠&#xff1b;风会使得照片模糊&#xff1b;外观会因成熟度&#xff0c;颜色&#xff0c;基因型和头部方向而异。使用图像处理和目标检测完成小麦头的位置的标定。完成训练并现场验证后上传指定的输出文件进行验证…

大数据NiFi(三):NiFi关键特性

文章目录 NiFi关键特性 一、​​​​​​​​​​​​​​流管理

人工智能轨道交通行业周刊-第28期(2022.12.26-2023.1.1)

本期关键词&#xff1a;NOCC、车站闸机、雾闪、2022年度盘点、智慧园区 1 整理涉及公众号名单 1.1 行业类 RT轨道交通中关村轨道交通产业服务平台人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网上榜铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通Rai…

安全—01day

DNS 域名解析过程: 1.浏览器首先查询浏览器的缓存&#xff0c;因为浏览器会按照一定的频率缓存 DNS 记录 2.若浏览器无缓存&#xff0c;那么查询操作系统的 HOST 文件&#xff0c;查询是否有 DNS 记录。 3.若还没有命中域名&#xff0c;就请求本地域名服务器该服务器一般都会缓…

Qt音视频开发07-合并音视频文件

一、前言 之前已经把音视频分开存储了对应的文件&#xff0c;因为这个需求特别少&#xff0c;当然确实有部分用户是需要把音视频分开存储&#xff0c;但是毕竟是很少数&#xff0c;绝大部分的用户都是音视频合并到一个MP4文件&#xff0c;所以如果要合并到一个文件&#xff0c…

二进制与十六进制的相互转换;按位操作:与() 和 或(|)

目录 一、二进制转换十六进制 二、十六进制转换二进制 三、按位操作&#xff1a;与&#xff08;&&#xff09; 和 或&#xff08;|&#xff09; 1、按位与&#xff08;&&#xff09;操作 2、按位或&#xff08;|&#xff09;操作 得出结论&#xff1a;清0用与&am…

【金猿案例展】海尔集团——追光AI-AOI赋能PCBA缺陷检测

‍数之联案例本项目案例由数之联投递并参与“数据猿年度金猿策划活动——《2022大数据产业年度创新服务企业》榜单/奖项”评选。‍数据智能产业创新服务媒体——聚焦数智 改变商业AOI&#xff08;Automated Optical Inspection缩写&#xff09;的中文全称是自动光学检测。通过…