leetcode刷题(6):二叉树的使用

文章目录

    • 104. 二叉树的最大深度
      • 解题思路
      • c++ 实现
    • 94. 二叉树的中序遍历
      • 解题思路
      • c++ 实现
    • 101. 对称二叉树
      • 解题思路
      • c++ 实现
    • 96. 不同的二叉搜索树
      • 解题思路
      • c++ 实现
    • 102. 二叉树的层序遍历
      • 解题思路
      • c++ 实现

104. 二叉树的最大深度

题目: 给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

示例:
在这里插入图片描述

解题思路

  • 没有左右子节点的节点,称为叶子节点
node->left ==nullptr && node->right ==nullptr`
  • 叶子节点所在的层数,就是从跟节点到叶子节点的距离
  • 统计遍历所有节点,找到叶子节点
    • 如果当前节点不是叶子节点,则判断该节点左节点或右节点是否叶子节点
    • 记录每个叶子节点,所在层数,找到最远距离的叶子节点

c++ 实现

class Solution {
public:
    int ans =0;
    void dfs(TreeNode* root, int level)
    {
        if (root ==nullptr) return;
        if(root->left==nullptr && root->right==nullptr)
        {
            ans = max(ans,level);
        }

        dfs(root->left,level+1);
        dfs(root->right,level+1);
    }
    int maxDepth(TreeNode* root) {
        dfs(root,1);
        return ans;
    }
};
  • 定义dfs函数,传入节点以及所在的层level; 因为当前节点所在的层等于跟节点到该节点的距离,可以用level来表示距离
  • 首先从跟节点root开始遍历,对应的level为1;
  • 如果到达叶子节点,则更新最远距离ans
  • 然后接着从root->left开始,以及root->right开始寻找叶子节点,当前节点所在层为level+1
  • 最终遍历完所有节点,找到最远距离ans

94. 二叉树的中序遍历

题目: 给定一个二叉树的根节点 root ,返回 它的 中序 遍历
示例:
在这里插入图片描述

解题思路

  • 中序遍历: left -> root ->right(左中右)
  • 递归遍历,首先考虑dfs

c++ 实现

class Solution {
public:
    vector<int> ans;

    void dfs(TreeNode* root)
    {
        if (root==nullptr) return;
        dfs(root->left);
        ans.push_back(root->val);
        dfs(root->right);
    }
    vector<int> inorderTraversal(TreeNode* root) {
       dfs(root);
        return ans;
    }
};
  • 完整c++ 调试代码
#include <iostream>
#include <vector>
using namespace std;

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x):val(x),left(nullptr),right(nullptr) {};
};

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root)
    {
        vector<int> result;
        inorder(root,result);
        return result;
    }
private:
    void inorder(TreeNode* root, vector<int>& result)
    {
        if (root == nullptr) return;
        inorder(root->left,result);
        result.push_back(root->val);
        inorder(root->right,result);
    }
};

int main()
{
    // 示例二叉树: 1 /   \ 2     3
    // 创建二叉树

    TreeNode* root = new TreeNode(1);
    root->left = new TreeNode(2);
    root->right = new TreeNode(3);

    // 使用中序遍历函数
    Solution solution;
    vector<int> inorderTraversalResult = solution.inorderTraversal(root);

    // 打印结果
    for (int val:inorderTraversalResult)
    {
        cout << val << " ";
    }

    // 清理内存
    delete root->left;
    delete root->right;
    delete root;

    return 0;
}



101. 对称二叉树

题目: 给你一个二叉树的根节点 root , 检查它是否轴对称。
示例:
在这里插入图片描述

解题思路


观察对称二叉树,查找满足对称的条件,可以发现

  • 对称树,它的子节左右对称,因此子节点需相同(如图红色的2和2)
  • 同时,子节点的孙子节点,左右两侧也要满足对称,即 left_tree->left = right_tree->right; left_tree->right = right_tree->left;
  • 找到规律后,递归遍历二叉树,判断二叉树是否对称。

参考:https://www.cnblogs.com/itdef/p/14400148.html

c++ 实现

class Solution {
public:
    bool dfs(TreeNode* l,TreeNode* r)
    {
    	//遍历到最后,都没有找到不相等的节点,那么就是对称的
        if(l==nullptr && r==nullptr) return true;
        if(l==nullptr && r !=nullptr) return false;
        if(l!=nullptr && r==nullptr) return false;
        if(l->val !=r->val) return false;
        // if(l->val ==r->val) return true; // 如果加了这一句,则这棵树遍历到存在左右节点相同,就不继续向下遍历了,因此不要加

        return dfs(l->left,r->right) && dfs(l->right,r->left); 
    }
    bool isSymmetric(TreeNode* root) {
        return dfs(root->left,root->right);
    }
};
  • 如果遍历过程中,左右存在任意不相等的,则直接判断不是对称树
  • 如果遍历到最后,都没有发现不相等。因为已经到树的最后,此时 l->leftr->right都为空,而且l->right和l->left也都是空, 根据if(l==nullptr && r==nullptr) return true;此时dfs(l->left,r->right) && dfs(l->right,r->left)返回true
  • 注意不要加:if(l->val ==r->val) return true, 不然遍历不到树的最后,只要在中间节点存在满足这一要求的,就停止判断了,无法对整棵树进行判断。

96. 不同的二叉搜索树

题目: 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?``返回满足题意的二叉搜索树的种数
示例:
在这里插入图片描述

解题思路

二叉搜索树, 也称二叉排序树二叉查找树。具有下列性质的二叉树:

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值
  • 它的左、右子树也分别为二叉排序树。
  • 二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势
  • 使用动态规划dp的方法求解, 设dp[n]记录n个连续节点(从 1 到 n 互不相同)组成的二叉搜索树的种类。
  • 二叉搜索树,左子树上的所有节点均小于它的跟节点,右子树上的所有节点均大于它的跟节点
  • 可知dp[1]1, 因为只有一个节点,排列的可能就只有一种;另外dp[0]也为1,因为也只有一种排列可能。dp[2] 可组成两种不同的搜索二叉树,因此dp[2]=2
    在这里插入图片描述
  • 对于3个节点,列出了所有的不同的搜索二叉树, 总共有5种
    • 如果1作为根节点,由于找不到比跟节点小的数作为左子树,因为左子树为空(dp[0]), 此时2,3两个节点在右子树上存在2种搜索二叉树的可能,也就是dp[2]:如果2在右子树上,那么3由于比2大,那么3只能是它的右子节点。如果3在右子树上,由于2比3小,2只能是它的左子节点); 此时种类数为: dp[0] * dp[2] = 2
      在这里插入图片描述
    • 如果2作为跟节点, 因为1比跟节点2小1只能是它的左节点,由于3比2大3只能是根节点2的右节点, 因此只有1种可能:因此种类计算为 dp[1]*dp[1] =1
    • 如果3作为跟节点,由于没有比它大的数,所以右子树为空,也就是dp[0],剩下的两个数字都在左子树上,对应为dp[2]: 如果1作为跟节点3的左节点,那么剩下的2只能是1的右节点(2比1大);如果2作为跟节点3的左子节点,那么剩下的1只能是2的左子节点(1比2小)。因此种类计算为 dp[2]*dp[0] =2
    • 所以对于3个节点来说,所有的二叉树为: dp[0] * dp[2] + dp[1]*dp[1] + dp[2]*dp[0] =5

因此得出如下规律:

  • (1)遍历每个数,作为根节点
  • (2) 计算该跟节点下,所有搜索二叉树的种类左子树(种类)* 右字数(种类)
  • (3) 最后将计算结果求和

c++ 实现

class Solution {
public:
    int numTrees(int n) {
        int dp[20]; 
        memset(dp,0x0,sizeof(dp));
        dp[0] =1;
        dp[1] =1;
        // 遍历p[i]
        for(int i=2;i<=n;i++)
        {   // i个节点,元素值 <=i; 遍历以每个节点作为跟节点
            for (int j=1;j<=i;j++)
            {
                dp[i] += dp[j-1] * dp[i-j];
            }
        }

        return dp[n];
    }
};
  • 首先初始化dp[20] , 并通过memset 置为0 ,因为n<=19, 初始化的大小足够了。
  • 其中:dp[0] 和dp[1] 都为1
  • 通过遍历 for(int i=2;i<=n;i++)来计算p[i]的值
  • 对于i个节点,元素值 <=i; 遍历以每个节点作为跟节点, 计算此时搜索二叉树的种类
dp[j-1] * dp[i-j]
  • 因为左节点元素小于根节点,所以为dp[j-1], 根据解题思路的总结,右节点对应为dp[i-j] , 因为j-1+i-j =i-1;

102. 二叉树的层序遍历

题目:给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

示例:
在这里插入图片描述

解题思路

BFS 广度优先搜索算法的介绍,看出博文: BFS和DFS优先搜索算法

  • BFS遍历二叉树 ,添加了遍历的树的层级level
  • 根据层级决定新开vector或者直接push

在这里插入图片描述

  • 先将跟节点root层级0,加入到队列queue中,然后遍历队列
  • 首先弹出根节点,并拿到节点值存储到ans中
  • 根节点下一层子节点加入队列
  • 然后继续弹出队列中的节点,如果节点层级大于curr节点,增需要重新开一个vector,存储该节点的值,如果和当前层级是一样的,则直接push_back到vector中。
  • 然后pop该节点,并将该节点的下一层子节点添加队
  • 继续上述步骤,直到全部遍历完。。。。

c++ 实现

class Solution {
public:
    vector<vector<int>> ans;
    int curr =0;       // current level
    vector<int> v;     // 单个level 保存的结果

    void bfs(TreeNode* root)
    {
        if(root==nullptr) return;

        //创建用来存储节点和level的queue
        queue<pair<TreeNode*,int>> q;
        // 放入第一个节点,同时记录节点的层级
        q.push({root,0});

        while(!q.empty())
        {
            // 循环弹出需要处理的节点
            TreeNode* p=q.front().first;
            int level = q.front().second;
            // 记得从队列中pop掉
            q.pop();

            // 如果处理的节点层级比当前vector层级更大
            // 那么说明上一层的节点数据已经处理完毕,需要重新开一个vector来记录新的层级节点
            if(level>curr)
            {
                // 更新curr 层级
                curr = level;
                // 将已经处理完毕的层级数据vector, 添加到ans结果中
                ans.push_back(v);
                // 得到一个空的vector, 用于记录新的层级数据
                v.clear();
                v.push_back(p->val);
            }
            else
            {
                //如果处理节点的层级和当前curr层级一样,直接push_back即可
                v.push_back(p->val);
            }
			// 将当前处理的节点的子节点,放入队列中,注意要加上子节点所在的层级
            if (p->left !=nullptr) q.push({p->left,level+1});
            if (p->right !=nullptr) q.push({p->right,level+1});
        }
        // 记得将最后一次的结果v,加入ans中
        ans.push_back(v);
        return;
    }
    vector<vector<int>> levelOrder(TreeNode* root) {
        bfs(root);
        return ans;
    }
};
  • 首先创建一个队列queue来节点及所在level, 并插入根节点
//创建用来存储节点和level的queue
queue<pair<TreeNode*,int>> q;
// 放入第一个节点,同时记录节点的层级
q.push({root,0});
  • 遍历队列,循环弹出需要处理的节点
// 循环弹出需要处理的节点
  TreeNode* p=q.front().first;
  int level = q.front().second;
  // 记得从队列中pop掉
  q.pop();
  • 如果处理的节点层级比当前vector层级更大,那么说明上一层的节点数据已经处理完毕,需要重新开一个vector记录新的层级节点
if(level>curr)
 {
       // 更新curr 层级
       curr = level;
       // 将已经处理完毕的层级数据vector, 添加到ans结果中
       ans.push_back(v);
       // 得到一个空的vector, 用于记录新的层级数据
       v.clear();
       v.push_back(p->val);
   }
  • 如果处理节点的层级和当前curr层级一样,直接push_back即可
 else
	  {
	       //如果处理节点的层级和当前curr层级一样,直接push_back即可
	       v.push_back(p->val);
	   }
  • 然后将pop掉的当前节点p的(下一层级)子节点加入队列queue, 同时它的level+1
if (p->left !=nullptr) q.push({p->left,level+1});
if (p->right !=nullptr) q.push({p->right,level+1});
  • 队列遍历完,记得将最后一次结果v加入到ans中
        // 记得将最后一次的结果,加入ans中
        ans.push_back(v);

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一文读懂deepSpeed:深度学习训练的并行化

引言 在深度学习领域&#xff0c;模型训练的过程不仅资源密集&#xff0c;而且技术复杂。近年来&#xff0c;随着模型规模和数据量的不断增长&#xff0c;深度学习训练面临着越来越多的挑战。这些挑战主要体现在计算资源的需求、训练效率、模型复杂度以及内存管理等多个方面。…

postgres 修改系统时间测试

修改系统时间 [rootmmsql01 ~]# date 2024年 05月 16日 星期四 13:07:02 CST [rootmmsql01 ~]# timedatectl set-time "2024-05-16 13:30:00" [rootmmsql01 ~]# date 2024年 05月 16日 星期四 13:30:03 CST [rootmmsql01 ~]# timedatectl set-time "2024-05-16…

基于QEMU-aarch64学习UEFI(EDK2)-2安装操作系统

1 基于QEMU-aarch64学习UEFI(EDK2)-2安装操作系统 文章目录 1 基于QEMU-aarch64学习UEFI(EDK2)-2安装操作系统1.1 二、基于qemu固件安装操作系统1.1.1 1、virt-manager安装1.1.2 2、创建虚拟机1.1.2.1 Ubuntu系统开机等待时间长问题解决 1.1.3 3、virt-manager日常使用1.1.4 4、…

GAN实例基于神经网络

目录 1.前言 2.实验 1.前言 需要了解GAN的原理查看对抗生成网络&#xff08;GAN&#xff09;&#xff0c;DCGAN原理。 采用手写数字识别数据集 2.实验 import argparse import os import numpy as np import mathimport torchvision.transforms as transforms from torchvi…

怎么把照片变小做头像?多种方法教你图片改尺寸

现在在社交媒体平台或者是社交软件上&#xff0c;我们经常会去更改头像来展示自己&#xff0c;但是有时候我们拍摄的照片太大无法直接用作头像&#xff0c;这时候就需要去修改图片尺寸&#xff0c;将图片改大小到合适的数值才能使用&#xff0c;那么如何快速的将图片改大小呢&a…

在UBuntu上安装QT环境

一、UBuntu环境 二、官网下载QT https://download.qt.io/archive/qt/ 安装所需选择版本下载&#xff0c;可以现在windows下载在复制进去 三、安装QT 1、复制到ubuntu 2、打开终端&#xff0c;改变刚下载文件的权限 权限代号 r&#xff1a;读取权限&#xff0c;数字代号为 “…

手机图片恢复不求人:手动找回丢失的照片!

无论是外出旅行、聚会还是日常点滴&#xff0c;我们总是习惯用手机记录下来&#xff0c;让美好的瞬间定格在一张张照片中。然而&#xff0c;有时因为误删、清空缓存或是更换手机&#xff0c;那些珍贵的照片突然消失了。手机图片恢复有什么简单易行、容易上手的方法吗&#xff1…

MySQL创建存储过程函数(2)

DDL CREATE TABLE student (id int(11) NOT NULL AUTO_INCREMENT COMMENT 学号,createDate datetime DEFAULT NULL,userName varchar(20) DEFAULT NULL,pwd varchar(36) DEFAULT NULL,phone varchar(11) DEFAULT NULL,age tinyint(3) DEFAULT NULL,sex char(2) DEFAULT NULL,i…

上海初中生古诗文大会倒计时4个月:单选题真题示例和独家解析

现在距离2024年初中生古诗文大会还有4个多月时间&#xff0c;备考要趁早&#xff0c;因为知识点还是相对比较多的。这些知识点对于初中语文的学习也是很有帮助的。 今天我们继续来看10道选择题真题和详细解析&#xff0c;以下题目截取自我独家制作的在线真题集&#xff0c;都是…

教你五行代码实现大批量文件重命名

问题背景 文件夹里的大量文件&#xff0c;命名很乱&#xff0c;并且要重新命名为固定长度顺序的文件很麻烦。这里采用5行python实现大批量文件按要求统一命名。 现有文件夹列表 tulips 代码实现 main.py import os path rtulips/ for num, file in enumerate(os.listdir(…

狙击策略专用术语以及含义,WeTrade3秒讲解

想必各位交易高手对狙击策略不会陌生吧!但你想必不知道狙击策略的开发者为了推广狙击策略&#xff0c;在狙击策略基础的经典技术分析理论引入了自己的术语。今天WeTrade众汇和各位投资者继续了解狙击策略专用术语以及含义。 一.BL 银行级别(BL)是前一日线收盘的级别。时间是格…

央视的AI动画《AI我中华》宣传视频,原来用AI工具Stable Diffusion制作,竟然这么简单?

大家好&#xff0c;我是向阳。 前段时间&#xff0c;央视的《爱我中华》AI宣传短片火爆全网&#xff0c;有一个穿越转场效果非常惊艳&#xff01;先来回顾回顾&#xff1a; 今天就先来详细讲解&#xff0c;如何利用Stable Diffusion制作这样的穿越转场视频。 如你还没有安装St…

脑中风也会出现眩晕?快速识别中风,一定要牢记这些!

眩晕是许多人都会经历的不适感&#xff0c;发作时仿佛整个世界都在旋转&#xff0c;可能还伴随着站立不稳、脚步虚浮、恶心等症状。然而&#xff0c;你可能不知道的是&#xff0c;这些症状在某些情况下可能是脑中风的前兆。如果不及时关注并采取相应措施&#xff0c;一旦发展为…

linux ndk编译搭建测试

一、ndk下载 NDK 下载 | Android NDK | Android Developers 二、ndk环境变量配置 ndk解压&#xff1a; unzip android-ndk-r26d-linux.zip 环境变量配置&#xff1a; export NDK_HOME/rd/own/test/android-ndk-r26d/ export PATH$PATH:$NDK_HOME 三、编译测试验证 …

003_PyCharm的安装与使用

如果你正在学习PyQt&#xff0c;本系列教程完全可以带你入门直至入土。 所谓从零开始&#xff0c;就是从软件安装、环境配置开始。 不跳过一个细节&#xff0c;不漏掉一行代码&#xff0c;不省略一个例图。 IDE 开始学习一个编程语言&#xff0c;我们肯定是首先得安装好它&…

【深度学习】【Lora训练2】StabelDiffusion,Lora训练过程,秋叶包,Linux,SDXL Lora训练

文章目录 一、如何为图片打标1.1. 打标工具1.1.1. 秋叶中使用的WD1.41.1.2. 使用BLIP21.1.3. 用哪一种 二、 Lora训练数据的要求2.1 图片要求2.2 图片的打标要求 三、 Lora的其他问题qa1qa2qa3qa4qa5 四、 对图片的处理细节4.1. 图片尺寸问题4.2. 图片内容选取问题4.3. 什么是一…

python批量生成防伪识别二维码

欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一.前言 二.代码 三.使用 四.总结 一.前言 二维码(QR Code)是一种矩阵条码技术,它使用黑白矩形图案来表示二进制数据,这些矩形图案可以被设备扫描并解读。二维码可以被用来存储

究极完整版!!Centos6.9安装最适配的python和yum,附带教大家如何写Centos6.9的yum.repos.d配置文件。亲测可行!

前言&#xff01; 这里我真是要被Centos6.9给坑惨了&#xff0c;最刚开始学习linux的时候并没有在意那么的&#xff0c;没有考虑到选版本问题&#xff0c;直到23年下半年&#xff0c;官方不维护Centos6.9了&#xff0c;基本上当时配置的文件和安装的依赖都用不了了&#xff0c…

springboot 引用外配置json文件

场景 一些服务需要记录一些持久化的信息&#xff08;没有数据库&#xff0c;redis&#xff0c;elasticsearch 可用&#xff09; 我们就项目启动过程创建一个json 文件去记录工作内容的进程&#xff08;json 可视化与改动非常方便&#xff09; 实现效果 代码 application.yml…

HashTable, HashMap, ConcurrentHashMap 三者区别

目录 1. HashMap 2. HashTable 3. ConcurrentHashMap 1. HashMap HashMap 是 Java 中非常常用的一个数据结构&#xff0c;它主要用于存储 键值对&#xff08;K&#xff0c;V&#xff09;。 在JDK 1.7中&#xff0c;HashMap的实现是基于 Table数组 和 Entry链表 的组合。 从…