算法Day17 | 110.平衡二叉树, 257. 二叉树的所有路径,404.左叶子之和

news/2024/11/22 17:15:11/

Day17

    • 110.平衡二叉树
    • 257. 二叉树的所有路径
    • 404.左叶子之和

110.平衡二叉树

题目链接:110.平衡二叉树
求高度,后序遍历。
递归 后序遍历
如果某一节点为非平衡二叉树,则整个二叉树就为非平衡二叉树,可以一直向上层递归-1

class Solution {
public:int recursion(TreeNode* cur) {if (!cur) return 0;//终止条件//左int left = recursion(cur->left);if (left == -1) return -1;//剪枝//右int right = recursion(cur->right);if (right == -1) return -1;//剪枝//中return (abs(left - right) > 1) ?  -1 : 1 + max(left, right);}bool isBalanced(TreeNode* root) {return recursion(root) != -1;}
};

迭代
层序遍历可以求深度(从上往下),但是不能求高度(从下往上)。
层序遍历各个节点,各个节点高度是通过后序遍历求出

class Solution {
public:int getHeight(TreeNode* cur) {stack<TreeNode*> st;if (cur) st.push(cur);int res = 0, height = 0;while (!st.empty()) {TreeNode* tmp = st.top();st.pop();if (tmp) {st.push(tmp); st.push(nullptr);//中++height;if(tmp->right) st.push(tmp->right);//右if(tmp->left) st.push(tmp->left);//左} else {st.pop();//出栈--height;//回溯}res = res > height ? res : height;}return res;}bool isBalanced(TreeNode* root) {stack<TreeNode*> st;if (!root) return true;else st.push(root);while (!st.empty()) {TreeNode* cur = st.top();st.pop();if (abs(getHeight(cur->left) - getHeight(cur->right)) > 1)return false;if (cur->right) st.push(cur->right);if (cur->left) st.push(cur->left);}return true;}
};

回溯法其实就是递归,但是很少人用迭代的方式去实现回溯算法!
因为对于回溯算法已经是非常复杂的递归了,如果再用迭代的话,就是自己给自己找麻烦,效率也并不一定高。


257. 二叉树的所有路径

题目链接: 257. 二叉树的所有路径
需要用深度遍历来求路径。深度遍历中,使用前序遍历。因为前序遍历的顺序为中左右,先遍历中间节点,再遍历子节点。
因为返回的为走过的路径。当找到第一条路径之后,寻找第二条路径,需要清除第一步路径走过的,直至清除剩余根节点。所以要回溯。
递归 前序遍历 回溯

class Solution {
public:void traversal(TreeNode* cur, vector<int>& path, vector<string>& res) {path.push_back(cur->val);//中if (!cur->left && !cur->right) {//终止条件string tmp;//处理前size-1个元素,留下最后一个元素。因为最后一个元素没有"->"for (int i = 0; i < path.size() - 1; ++i) {tmp += to_string(path[i]);tmp += "->";}res.push_back(tmp + to_string(path[path.size() - 1]));//加上最后一个元素return;}if (cur->left) {//左traversal(cur->left, path, res);path.pop_back();//回溯}if (cur->right) {//右traversal(cur->right, path, res);path.pop_back();//回溯}}vector<string> binaryTreePaths(TreeNode* root) {vector<string> res;vector<int> path;traversal(root, path, res);return res;}
};

上述代码需要回溯,是因为每条路走完,最后的路径存储到path中,从path中提取int,再统一处理成string形式。
也可以每一步都处理string,而不是最后在统一处理成string,则不需要对path进行回溯。
递归 没有回溯

class Solution {
public:void traversal(TreeNode* cur, string& path, vector<string>& res) {path += to_string(cur->val);if (!cur->left && !cur->right) {res.push_back(path);return;}if (cur->left){string tmp = path + "->";traversal(cur->left, tmp, res);}if (cur->right) {string tmp = path + "->";traversal(cur->right, tmp, res);}}vector<string> binaryTreePaths(TreeNode* root) {vector<string> res;string path;traversal(root, path, res);return res;}
};

下述代码中,string path不能改为string& path,因为传值时,只操作当前函数中path,传址,则操作整个递归过程中的path

class Solution {
private:void traversal(TreeNode* cur, string path, vector<string>& result) {path += to_string(cur->val); // 中,中为什么写在这里,因为最后一个节点也要加入到path中if (!cur->left && !cur->right) {result.push_back(path);return;}if (cur->left) {path += "->";traversal(cur->left, path, result); // 左path.pop_back(); // 回溯 '>'path.pop_back(); // 回溯 '-'}if (cur->right) {path += "->";traversal(cur->right, path, result); // 右path.pop_back(); // 回溯'>'path.pop_back(); // 回溯 '-'}}
public:vector<string> binaryTreePaths(TreeNode* root) {vector<string> result;string path;traversal(root, path, result);return result;}
};

前序遍历,需要多一个辅助stack来保存路径上的节点。为什么要用stack呢,保证与前序遍历相同的处理方式。
迭代 前序遍历

class Solution {
public:vector<string> binaryTreePaths(TreeNode* root) {vector<string> res;stack<string> stS;//保存路径的节点stack<TreeNode*> stT;stT.push(root);stS.push(to_string(root->val));while (!stT.empty()) {TreeNode* cur = stT.top();stT.pop();//中string path = stS.top();stS.pop();if (!cur->left && !cur->right) {res.push_back(path);}if (cur->right) {//右stT.push(cur->right);stS.push(path + "->" + to_string(cur->right->val));}if (cur->left) {//左stT.push(cur->left);stS.push(path + "->" + to_string(cur->left->val));}}return res;}
};

404.左叶子之和

题目链接:404.左叶子之和
判断节点是否为叶子节点,判断该节点左右子节点是否为空。
如何判断节点是否为左叶子,则需要通过该节点的父节点来判断,对于父节点来说,左子节点的左右子节点为空。
递归 后序遍历

class Solution {
public:int sumOfLeftLeaves(TreeNode* root) {if (!root) return 0;if (!root->left && !root->right) return 0;int left = sumOfLeftLeaves(root->left);//左//判断左节点是否为叶子节点if (root->left/*左节点存在*/ && !root->left->left && !root->left->right/*左节点的左右节点不存在*/)left = root->left->val;int right = sumOfLeftLeaves(root->right);//右return left + right;//中}
};

迭代 前序遍历

class Solution {
public:int sumOfLeftLeaves(TreeNode* root) {stack<TreeNode*> st;st.push(root);int res = 0;while (!st.empty()) {TreeNode* cur = st.top();//中st.pop();if (cur->left && !cur->left->left && !cur->left->right)res += cur->left->val;if (cur->right) st.push(cur->right);//右if (cur->left) st.push(cur->left);//左}return res;}
};

http://www.ppmy.cn/news/89418.html

相关文章

从零开始搭建高效的文件服务器:FastDFS与Nginx完美结合,内网穿透实现公网访问

目录 前言 1. 本地搭建FastDFS文件系统 1.1 环境安装 1.2 安装libfastcommon 1.3 安装FastDFS 1.4 配置Tracker 1.5 配置Storage 1.6 测试上传下载 1.7 与Nginx整合 1.8 安装Nginx 1.9 配置Nginx 2. 局域网测试访问FastDFS 3. 安装cpolar内网穿透 4. 配置公网访问…

ChatGPT之公文写作

公务文章主要适用于政府部门、机关、事业单位以及其他公共组织的文件、公告、通知等文稿。 根据《党政机关公文处理工作条例》&#xff0c;公文种类主要有15种。按照行文流向&#xff0c;可以分为上行文、平行文、下行文。 1、上行文&#xff1a;请示、报告、意见。 2、平行…

分享去年学习github命令行操作的笔记

git branch -M main 给远程分支改名 一、本地库操作 1.创建本地目录&#xff0c;用于存储要上传的文本文件。可以手动创建也可以用带命令行 mkdir <文件名> 2.进入文件夹cd <文件名> 3第一次创建时需要初始化仓库git init mac显示隐藏文件SHIFTCOMMAND. mac…

如何在宝塔面板后的阿里云服务器运行Flask项目并公网可以访问?

在你的服务器安装宝塔面板 宝塔面板是服务器运维管理系统 使用宝塔前&#xff1a; 手工输入命令安装各类软件&#xff0c;操作起来费时费力并且容易出错&#xff0c;而且需要记住很多Linux的命令&#xff0c;非常复杂。 使用宝塔后&#xff1a; 2分钟装好面板&#xff0c;一键…

可分析表情和情绪的轻量化眼镜:Emteq OCOsense解析

近年来&#xff0c;越来越多VR头显开始尝试结合眼球追踪、手势追踪等生物识别技术&#xff0c;甚至在一些VR社交场景&#xff0c;也在探索将Avatar与面部识别功能结合。可以想象&#xff0c;未来生物识别与AR/VR等穿戴技术的关系将越来越紧密&#xff0c;尽管现阶段相关硬件在体…

4EVERLAND 与 Sei 合作:用去中心化存储赋能最快的 L1

我们很高兴地宣布我们与 Sei 的合作&#xff0c;Sei 是最快的第 1 层交易。 该合作伙伴关系旨在优化架构&#xff0c;在现有最快的区块链上为所有类型的去中心化应用程序提供最佳的去中心化存储功能。 4EVERLAND&#xff0c;Sei的一站式去中心化存储基础设施 4EVERLAND是一个…

WSL 双系统端口映射,网络穿透最新教程

目录 1 进入wsl 1.1 进入root模式 1.2 随便安装个东西 2 打开win的PowerShell 2.1 查看虚拟机的ip地址 2.2 端口映射转发 2.3 验证是否成功 2.4 删除映射端口命令 1 进入wsl 这里使用的是ubuntuLiunx操作系统 打开wsl&#xff0c;搜索即可。 1.1 进入root模式 命令 …

Linux 中的 kill 命令

在Linux系统中&#xff0c;kill是一个用于发送信号给进程的命令。默认情况下&#xff0c;kill命令会发送SIGTERM信号给指定进程&#xff0c;要求进程安全退出。如果进程没有响应该信号&#xff0c;可以尝试使用其他信号&#xff08;例如SIGKILL&#xff09;来强制关闭它。 以下…