【算法与数据结构】110、LeetCode平衡二叉树

news2024/10/6 8:39:18

文章目录

  • 一、题目
  • 二、解法
  • 三、完整代码

所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。

一、题目

在这里插入图片描述
在这里插入图片描述

二、解法

  思路分析:二叉树遍历一共有前中后遍历和层序遍历,这道题只有后序遍历适合,求深度是从上往下查,求高度是从下往上查,因此后序遍历适合。这里利用了笔者的另外一篇文章的后序遍历算法【算法与数据结构】144、94、145LeetCode二叉树的前中后遍历(递归法、迭代法)。在这个后序遍历算法的基础上,添加了计算节点高度的函数,calc_height函数使用了递归法。首先要知道节点高度等于左右节点高度取最大值+1,这是我们使用递归法计算节点高度的基础:

max(Lheight, Rheight)+1;

递归法的三个要素:1.返回值为节点高度,输入参数为节点变量 2.终止条件为空节点或者是叶子节点 3.单层递归是返回左右节点高度取最大值+1,程序当中可以看到笔者将节点类型分为了五种:

  • 空节点
  • 叶子节点
  • 左节点为空,右节点非空
  • 左节点非空,右节点为空
  • 左右节点均非空
      实际上只有两种,除了空节点这一种类型外,其余四种可以归为一类,单层递归都可以包含在内。但是在LeetCode上跑代码的结果来看,空节点和叶子节点单独列出,直接返回,最节省时间。
      最终程序如下
class Solution {
public:
    // 递归法 三步法:1 、确定返回值和输入参数 2、 确定终止条件 3、确定单层递归逻辑
    int calc_height(TreeNode* root) {   // 计算节点高度
        if (!root) return 0;                            // 1.空节点高度为0
        else if (!(root->left) && !(root->right)) return 1;  // 2.碰到叶子节点返回,叶子节点高度为1
        //else if (!(root->left) && root->right) return 1 + calc_height(root->right);   // 3.左节点为空,右节点非空
        //else if (root->left && !(root->right)) return 1 + calc_height(root->left);   // 4.左节点非空,右节点为空
        else return 1 + max(calc_height(root->left), calc_height(root->right));
    }
    bool isBalanced(TreeNode* root) {
        // 后序遍历,统一风格写法
        stack<TreeNode*> st;
        if (root != NULL) st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop();
                st.push(node);                          // 中
                st.push(NULL);
                if (node->right) st.push(node->right);  // 右
                if (node->left) st.push(node->left);    // 左
            }
            else {
                st.pop();
                node = st.top();
                st.pop();
                if (abs(calc_height(node->left) - calc_height(node->right)) > 1) return false;
            }
        }
        return true;
    }
};

  更为精简的版本程序如下,如果当前节点的左右子树高度差值大于1,那么在计算下去也没有意义了,我们直接返回-1。

class Solution2 {
public:
    // 后序遍历
    int calc_height(TreeNode* root) {
        if (!root) return 0;
        int Lheight = calc_height(root->left);
        if (Lheight == -1) return -1;
        int Rheight = calc_height(root->right);
        if (Rheight == -1) return -1;
        return abs(Lheight - Rheight) > 1 ? -1 : 1 + max(Lheight, Rheight);
    }
    bool isBalanced(TreeNode* root) {
        return calc_height(root) == -1 ? false : true;
    }
};

三、完整代码

# include <iostream>
# include <vector>
# include <queue>
# include <string>
# include <algorithm>
# include <stack>
using namespace std;

// 树节点定义
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:
    // 递归法 三步法:1 、确定返回值和输入参数 2、 确定终止条件 3、确定单层递归逻辑
    int calc_height(TreeNode* root) {   // 计算节点高度
        if (!root) return 0;                            // 1.空节点高度为0
        else if (!(root->left) && !(root->right)) return 1;  // 2.碰到叶子节点返回,叶子节点高度为1
        //else if (!(root->left) && root->right) return 1 + calc_height(root->right);   // 3.左节点为空,右节点非空
        //else if (root->left && !(root->right)) return 1 + calc_height(root->left);   // 4.左节点非空,右节点为空
        else return 1 + max(calc_height(root->left), calc_height(root->right));
    }
    bool isBalanced(TreeNode* root) {
        // 后序遍历,统一风格写法
        stack<TreeNode*> st;
        if (root != NULL) st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop();
                st.push(node);                          // 中
                st.push(NULL);
                if (node->right) st.push(node->right);  // 右
                if (node->left) st.push(node->left);    // 左
            }
            else {
                st.pop();
                node = st.top();
                st.pop();
                if (abs(calc_height(node->left) - calc_height(node->right)) > 1) return false;
            }
        }
        return true;
    }
};

class Solution2 {
public:
    // 后序遍历
    int calc_height(TreeNode* root) {
        if (!root) return 0;
        int Lheight = calc_height(root->left);
        if (Lheight == -1) return -1;
        int Rheight = calc_height(root->right);
        if (Rheight == -1) return -1;
        return abs(Lheight - Rheight) > 1 ? -1 : 1 + max(Lheight, Rheight);
    }
    bool isBalanced(TreeNode* root) {
        return calc_height(root) == -1 ? false : true;
    }
};

void my_print(vector <string>& v, string msg)
{
    cout << msg << endl;
    for (vector<string>::iterator it = v.begin(); it != v.end(); it++) {
        cout << *it << "  ";
    }
    cout << endl;
}

void my_print2(vector<vector<int>>& v, string str) {
    cout << str << endl;
    for (vector<vector<int>>::iterator vit = v.begin(); vit < v.end(); ++vit) {
        for (vector<int>::iterator it = (*vit).begin(); it < (*vit).end(); ++it) {
            cout << *it << ' '; 
        }
        cout << endl;
    }
}

// 前序遍历迭代法创建二叉树,每次迭代将容器首元素弹出(弹出代码还可以再优化)
void Tree_Generator(vector<string>& t, TreeNode*& node) {
    if (t[0] == "NULL" || !t.size()) return;    // 退出条件
    else {
        node = new TreeNode(stoi(t[0].c_str()));    // 中
        t.assign(t.begin() + 1, t.end());
        Tree_Generator(t, node->left);              // 左
        t.assign(t.begin() + 1, t.end());
        Tree_Generator(t, node->right);             // 右
    }
}

// 层序遍历
vector<vector<int>> levelOrder(TreeNode* root) {
    queue<TreeNode*> que;
    if (root != NULL) que.push(root);
    vector<vector<int>> result;
    while (!que.empty()) {
        int size = que.size();  // size必须固定, que.size()是不断变化的
        vector<int> vec;
        for (int i = 0; i < size; ++i) {
            TreeNode* node = que.front();
            que.pop();
            vec.push_back( node->val);
            if (node->left) que.push(node->left);   
            if (node->right) que.push(node->right);
        }
        result.push_back(vec);
    }
    return result;
}

int main()
{
    vector<string> t = { "3", "9", "NULL", "NULL", "20", "15", "NULL", "NULL", "7", "NULL", "NULL"};   // 前序遍历
    //vector<string> t = { "1", "2", "3", "4", "NULL", "NULL", "4", "NULL", "NULL", "3", "NULL", "NULL", "2", "NULL", "NULL" };   // 前序遍历
    my_print(t, "目标树");
    TreeNode* root = new TreeNode();
    Tree_Generator(t, root);
    vector<vector<int>> tree = levelOrder(root);
    my_print2(tree, "目标树:");
    Solution s1;
    bool result = s1.isBalanced(root);
    cout << "是否平衡:";
    if (result) cout << "是" << endl;
    else cout << "否" << endl;
    system("pause");
    return 0;
}

end

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

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

相关文章

【小黄碎碎念】如何解析和替换字符串中的 Markdown 文本?正则表达式与 flexmark-java 库

前言 本周&#xff0c;笔者将之前的基于 Servlet 的个人博客项目进行了迭代&#xff0c;基于 SpringBoot SpringMVC Mybatis Redis 进行实现。额外实现密码的明文加密处理&#xff08;加盐算法&#xff09;、修改博客、公共主页等功能&#xff0c;并将 session 存储到 Redis…

深度学习——批标准化Batch Normalization

什么是批标准化&#xff1f; 批标准化&#xff08;Batch Normalization&#xff09;是深度学习中常用的一种技术&#xff0c;旨在加速神经网络的训练过程并提高模型的收敛速度。 批标准化通过在神经网络的每一层中对输入数据进行标准化来实现。具体而言&#xff0c;对于每个输…

我在VScode学Python(Python函数,Python模块导入)

我的个人博客主页&#xff1a;如果’真能转义1️⃣说1️⃣的博客主页 &#xff08;1&#xff09;关于Python基本语法学习---->可以参考我的这篇博客《我在VScode学Python》 &#xff08;2&#xff09;pip是必须的在我们学习python这门语言的过程中Python ----&#xff1e;&a…

fl studio 20如何设置中文汉化汇总及flstudio21水果language选项中文设置方法

fl studio这是一个编曲软件&#xff0c;它有中文和英文两种语言供大家选择&#xff0c;对我们来说&#xff0c;中文版肯定更方便。fl studio如何设置中文&#xff1f;事实上&#xff0c;只需在设置中切换中文即可。 我们一起 fl studio 20如何设置中文一些方法 一、fl studio手…

Angular:动态依赖注入和静态依赖注入

问题描述&#xff1a; 自己写的服务依赖注入到组件时候是直接在构造器内初始化的。 直到看见代码中某大哥写的 private injector: Injector 动态依赖注入和静态依赖注入 在 Angular 中&#xff0c;使用构造函数注入的方式将服务注入到组件中是一种静态依赖注入的方式。这种方…

docker中搭建lnmp

目录 一&#xff1a;项目环境 1、主机ip需求 2、 任务需求 二&#xff1a;多级构建Dockerfile实验部署 lnmp 1、先部署一个有所有依赖包的镜像 2、搭建nginx 3、搭建mysql 4、搭建php 三&#xff1a;一级构建安装lnmp 1、构建自定义docker网络 2、构建nginx容器&#x…

办公室安全升级,如何保障人身财产安全?

视频监控&#xff0c;一种常见的安全措施&#xff0c;以监视和记录办公室内的活动。这项技术为企业提供了许多优势&#xff0c;包括保障员工和财产安全、帮助调查犯罪事件、提高业务管理效率以及应对突发事件。 因此&#xff0c;在合理范围内应用视频监控&#xff0c;将为企业提…

LINUX中的myaql(一)安装

目录 前言 一、概述 二、数据库类型 三、数据库模型 四、MYSQL的安装 &#xff08;一&#xff09;yum安装MYSQL &#xff08;二&#xff09;rpm安装MYSQL 五、MYSQL本地登录 rpm安装MYSQL本地登录 六、重置密码 总结 前言 MySQL是一种常用的开源关系型数据库管理系统&#xff…

泛微OA客戶管理融合呼叫中心系统功能

泛微OA&#xff0c;全程数字化运营平台。用户因业务管理需要&#xff0c;crm客户管理流程中&#xff0c;需要通过语音与客户沟通&#xff0c;对话务沟通过程实现流程和过程化管理。 泛微OA中&#xff0c;无需过多编程代码。通过呼叫中心接口快速开发&#xff0c;实现点击拨打&…

【计算机网络】第 3 课 - 计算机网络体系结构

欢迎来到博主 Apeiron 的博客&#xff0c;祝您旅程愉快 &#xff01; 时止则止&#xff0c;时行则行。动静不失其时&#xff0c;其道光明。 目录 1、常见的计算机网络体系结构 2、计算机网络体系结构分层的必要性 2.1、物理层 2.2、数据链路层 2.3、网路层 2.4、运输层 2…

融合正余弦和柯西变异的麻雀搜索算法优化CNN-BiLSTM,实现多输入单输出预测,MATLAB代码...

上期作者推出的融合正余弦和柯西变异的麻雀优化算法&#xff0c;效果着实不错&#xff0c;今天就用它来优化一下CNN-BiLSTM。CNN-BiLSTM的流程&#xff1a;将训练集数据输入CNN模型中&#xff0c;通过CNN的卷积层和池化 层的构建&#xff0c;用来特征提取&#xff0c;再经过BiL…

(20)操纵杆或游戏手柄

文章目录 前言 20.1 你将需要什么 20.2 校准 20.3 用任务规划器进行设置 20.4 飞行前测试控制装置 20.5 测试失控保护 20.6 减少控制的滞后性 前言 本文解释了如何用操纵杆或游戏手柄控制你的飞行器&#xff0c;使用任务计划器向飞行器发送"RC Override"消息…

【C++基础(六)】类和对象(中) --构造,析构函数

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C初阶之路⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; 类和对象-中 1. 前言2. 构造函数3. 构造函数的特性4…

Opencv 细节补充

1.分辨率的解释 •像素&#xff1a;像素是分辨率的单位。像素是构成位图图像最基本的单元&#xff0c;每个像素都有自己的颜色。 •分辨率&#xff08;解析度&#xff09;&#xff1a; a) 图像分辨率就是单位英寸内的像素点数。单位为PPI(Pixels Per Inch) b) PPI表示的是每英…

从零开始 Spring Cloud 7:Gateway

从零开始 Spring Cloud 7&#xff1a;Gateway 图源&#xff1a;laiketui.com Spring Cloud Gateway 是 Spring Cloud 的一个全新项目&#xff0c;该项目是基于 Spring 5.0&#xff0c;Spring Boot 2.0 和 Project Reactor 等响应式编程和事件流技术开发的网关&#xff0c;它旨…

系统集成|第三章(笔记)

目录 第三章 系统集成专业技术3.1 信息系统建设3.1.1 信息系统3.1.2 信息系统集成 3.2 信息系统设计3.3 软件工程3.4 面向对象系统分析与设计3.5 软件架构3.5.1 软件的架构模式3.5.2 软件中间件 3.6 典型应用集成技术3.6.1 数据库与数据仓库技术3.6.2 Web Services 技术3.6.3 J…

区间预测 | MATLAB实现基于QRF随机森林分位数回归时间序列区间预测模型

区间预测 | MATLAB实现基于QRF随机森林分位数回归时间序列区间预测模型 目录 区间预测 | MATLAB实现基于QRF随机森林分位数回归时间序列区间预测模型效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现基于QRF随机森林分位数回归时间序列区间预测模型&#xff1…

SpringCloud学习路线(10)——分布式搜索ElasticSeach基础

一、初识ES &#xff08;一&#xff09;概念&#xff1a; ES是一款开源搜索引擎&#xff0c;结合数据可视化【Kibana】、数据抓取【Logstash、Beats】共同集成为ELK&#xff08;Elastic Stack&#xff09;&#xff0c;ELK被广泛应用于日志数据分析和实时监控等领域&#xff0…

java——继承

&#x1f384;&#x1f384;&#x1f384;继承 &#x1f346;&#x1f346;继承的概念&#xff1a; 继承(inheritance)机制&#xff1a;是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类&#xff08;父类&#xff09;特性的基础上进行扩展…