二叉数题型2

news2024/12/23 2:59:19

目录

二叉搜索树的众数

二叉树的最近公共祖先

修剪二叉树


二叉搜索树的众数

问题描述:

给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。如果树中有不止一个众数,可以按 任意顺序 返回。

 思路1:运用STL中的容器map,vector来辅助解决。通过遍历二叉树,将其放入map中,map可以统计每个key对应的value值。但map是对key排序的,所以再将每个键值对放入vector中,让vector对value值进行排序。

对应代码:

class Solution {
public:
    map<int,int> m_;
    void _preoder(TreeNode* root)
    {
        if(root==nullptr)
          return;
        if(root!=nullptr)
          m_[root->val]++;
        _preoder(root->left);
        _preoder(root->right);
    }
    bool static cmp(const pair<int,int>&a,const pair<int,int>& b)
    {
        return a.second>b.second;//按从大到小排序
    }
    vector<int> findMode(TreeNode* root) {
    
      _preoder(root);
      vector<pair<int,int>> v_(m_.begin(),m_.end());
      sort(v_.begin(),v_.end(),cmp);
      vector<int> result;
      result.push_back(v_[0].first);     //其中一个众数
      for(int i=1;i<v_.size();i++)
      {
          if(v_[i].second==v_[i-1].second)// 可能有多个众数
           result.push_back(v_[i].first);
          else
           break;
      }
      return result; 
    }
};

思路2因为是二叉搜索数,所以按中序遍历的顺序去遍历时,是按从小到大的顺序访问的,可以去比较相近的两个元素是否相等,统计最大的次数。

中序遍历的框架与上文介绍的是一样的:

TreeNode* pre=nullptr;
void _findMode(TreeNode* cur)
{
    if(cur==nullptr)
      return;
    _findMode(cur->left);
   if(pre==nullptr)
    cur=pre;
   else
  //处理节点
     _findMode(cur->right);
}

用两个变量分别记录当前遍历到的元素个数,和当前最多的元素的个数。将出现最多的元素放入vector中。例如:

class Solution {
public:
 TreeNode* pre=nullptr;  
 vector<int> result;
 int count=0;
 int maxcount=0;
void _findMode(TreeNode* cur)
{
    if(cur==nullptr)
      return;
    _findMode(cur->left);
    if(pre==nullptr)         //若pre为空,则cur刚找到最小的元素,此时count置位1
      count=1;
    else if(pre->val==cur->val)  //前后两元素相同,则count++
      count++;
    else                      //重新计数
     count=1;
    pre=cur;
    if(count==maxcount)      //说明出现了多个相同次数的元素
     result.push_back(cur->val);
    if(count>maxcount)       //后面出现的元素次数更大,把之前加入的元素清空,重新加入
    {
        result.clear();
        result.push_back(cur->val);
        maxcount=count;
    }

     _findMode(cur->right);
}
    vector<int> findMode(TreeNode* root) {
    
    TreeNode* cur=root;
    _findMode(cur);
    return result;
    }
};

这种方法只需要遍历一次二叉树即可。

二叉树的最近公共祖先

题目描述:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大

思路1:分别寻找p,q是在当前的节点的左边还是右边。因为题目给定的p,q两个节点必定存在公共祖先。情况1:当前节点就是p或者q,那么当前节点就是祖先。情况 2:p,q分别在当前节点的两边,那么当前节点就是祖先。情况3:p,q节点都在当前节点的左边或者右边,那么当前节点往左或者右边遍历,重复上面的的操作。

class Solution {
public:
  bool _istree(TreeNode*root,TreeNode*node)  //确定p,q节点是否在当前节点下
  {
      if(root==nullptr)
        return false;
     if(node==root)
       return true;
    return _istree(root->left,node)||_istree(root->right,node);
      
  }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(p==root||q==root)
          return root;
        bool pinleft=_istree(root->left,p);
        bool pinright=!pinleft;
        bool qinleft=_istree(root->left,q);
        bool qinright=!qinleft;

        if((pinleft&&qinright)||(pinright&&qinleft))
          return root;
        else if(pinleft&&qinleft)
          return lowestCommonAncestor(root->left,p,q);
        else if(pinright&&qinright)
         return lowestCommonAncestor(root->right,p,q);
        else
         {}
     return nullptr;
    }
};

上面的思路很好理解,但是若p,q节点都是叶子节点,都是兄弟节点。那么上面的代码时间复杂度就会很高。 (lowestCommonAncestor)每往后走一步,(_istree)都要遍历到最后才能找到,(lowestCommonAncestor)也要走到最后,就是p,q的父亲节点才能结束。

思路2:若是可以通过自底向上去查找就更容易了,可以模拟二叉树后序遍历的过程。把找到的结果返回给上一层。

例如:

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {

        if(root==nullptr||root==p||root==q)//终止条件
         return root;
        TreeNode* left=lowestCommonAncestor(root->left,p,q);
        TreeNode* right=lowestCommonAncestor(root->right,p,q);

        if(left!=nullptr&&right!=nullptr)   //找到了结果,返回
         return root;
        else if(left==nullptr&&right==nullptr)
         return nullptr;
        else if(left!=nullptr)
         return left;
        else
         return right;
        
    }
};

思路3:从头节点开始找到每个节点的路径,然后再去找到路径上的共同节点。

class Solution {
public:
     bool findpath(TreeNode* root,TreeNode* x,stack<TreeNode*>& Path)
     {   
         if(root==NULL)
          return false;
         Path.push(root);
         if(root==x)
           return true;
         if(findpath(root->left,x,Path))
            return true;
         if(findpath(root->right,x,Path))
            return true;

        Path.pop();
        return false;
       
     }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        
        stack<TreeNode*>ppath,qpath;
        findpath(root,p,ppath);
        findpath(root,q,qpath);
       while(ppath.size()>qpath.size())
       {
           ppath.pop();
       }
       while(ppath.size()<qpath.size())
       {
           qpath.pop();
       }
        while(ppath.top()!=qpath.top())
        {
            ppath.pop();
            qpath.pop();
        }
        return ppath.top();
    }
};

修剪二叉树

题目描述:给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 

思路:

 

 可能很容易写出这样的代码:直接判断当前节点是否满足条件,如不满足,这直接将左孩子或右孩子返回。

例如:

class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int low, int high) {
        
    if(root==nullptr)
     return nullptr;
    if(root->val<low)
      return right;
    if(root->val>high)
      return left;

     root->left=trimBST(root->left,low,high); //条件满足,则继续递归当前节点的左右孩子,对其修剪
     root->right=trimBST(root->right,low,high);
     return root;                             //返回当前节点给上一层
 
    }
};

这样的话并没有把节点值3给删除点,正确的做法是,例如当前节点的值已经小于low,那么它的右孩子也可能小于low或者它的右子树中有节点小于low.它的左子树肯定不满足条件了。后面要对它的右子树进行修建,接受它的右子树的返回值,再将结果返回给上一层。

代码:

class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int low, int high) {
        
    if(root==nullptr)
     return nullptr;
    if(root->val<low)
    {
        TreeNode* right=trimBST(root->right,low,high);  //对右子树进行修剪
        return right;                  //当前节点已不满足条件,接收右子树返回值,再返回
    } 
    if(root->val>high)
    {
        TreeNode* left=trimBST(root->left,low,high);   //对左子树修剪
        return left;                   //当前节点已不满足条件,接收左子树返回值,再返回
    }

    root->left=trimBST(root->left,low,high);//条件满足,则继续递归当前节点的左右孩子,对其修剪
    root->right=trimBST(root->right,low,high);
    return root;                       //返回当前节点给上一层

    }
};

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

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

相关文章

PROJ 9.1.1源码下载编译(Win10+VS2022)

目录PROJ什么是PROJPROJ下载方式资源结构编译PROJ打包编译成功的库PROJ 什么是PROJ Proj是一个免费的GIS工具。 它专注于地图投影的表达&#xff0c;以及转换。采用一种非常简单明了的投影表达PROJ&#xff0c;比其它的投影定义简单&#xff0c;但很明显。很容易就能看到各种…

无人机倾斜摄影测量技术的优势有哪些?

传统的地理信息获取工作一般是通过人工测量的方式进行&#xff0c;但这样的测量方式具有工作强度大、成本高等问题。随着现代科技的不断发展&#xff0c;测绘行业对地理信息数据的准确性、时效性要求也越来越高&#xff0c;人工成本和时间成本也为行业带来了巨大的压力。因此&a…

GIT回退到指定版本的两种方法(reset/revert)

实现多人合作程序开发的过程中&#xff0c;我们有时会出现错误提交的情况&#xff0c;此时我们希望能撤销提交操作&#xff0c;让程序回到提交前的样子&#xff0c;本文总结了两种解决方法&#xff1a;reset、revert。 命令特点reset该命令会强行覆盖当前版本和要回退的版本之…

ArcGIS基础实验操作100例--实验15设置字段属性域

本实验专栏来自于汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 基础编辑篇--实验15 设置字段属性域 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&a…

如何用Sonic云真机打王者

使用Sonic进行跨网段部署&#xff0c;助力海外业务的公司进行专项检测。提供定时任务充分利用无人值守时间回归UI测试&#xff0c;省时省力。自研随机事件测试与UI遍历测试&#xff0c;支持打通Jenkins的DevOps流程&#xff0c;Sonic提供图像识别&#xff0c;后续还会添加poco控…

ECS-弹性容器服务 - Part 2

68-ECS-弹性容器服务 - Part 2 Hello大家好&#xff0c;我们今天继续ECS的内容。 Service load balancing 之前的课时讨论过&#xff0c;在ECS集群上创建的ECS服务支持AWS负载均衡器&#xff0c;而应用程序负载均衡器和ECS服务通常是一个很好的搭配&#xff0c;因为应用程序负…

Docker 基础概念介绍

一 什么是 docker &#xff1f; Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中&#xff0c;然后发布到任何流行的 Linux或Windows操作系统的机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;…

【nowcoder】笔试强训Day13

目录 一、选择题 二、编程题 2.1参数解析 2.2跳石板 一、选择题 1.一个关系数据库文件中的各条记录 &#xff08;&#xff09; 。 A. 前后顺序不能任意颠倒&#xff0c;一定要按照输入的顺序排列 B. 前后顺序可以任意颠倒&#xff0c;不影响库中的数据关系 C. 前后顺序…

前端面试题之计算机网络篇--HTTP协议

HTTP协议 1. GET和POST的请求的区别 GET和POST方法 GET和POST方法都是HTTP中的方法 什么是 HTTP&#xff1f; 超文本传输协议&#xff08;Hypertext Transfer Protocol&#xff0c;缩写 HTTP&#xff09;旨在启用客户端和服务器之间的通信。 HTTP 充当客户端和服务器之间的…

Android进阶——Javac编译解析

Javac编译器 1.Javac的源码与调试 Javac的源码下载地址&#xff1a;Javac的源码下载地址&#xff0c;在Myeclipse中新建项目Compiler_javac&#xff0c;把源码复制到项目中。 Javac的源码目录&#xff1a; 从Sun Javac的代码来看&#xff0c;编译过程大致可以分为3个过程&…

测试工程师正遭「革命」 AI将改写测试模式

文章目录❤️‍&#x1f525; 软件测试的现状❣️ 功能测试的短板❣️ 过于的依赖工具❤️‍&#x1f525; 测试行业的两极分化❤️‍&#x1f525; 纯功能测试人员应该如何破局❣️ 龙测 AI TestOps 云平台❣️ AI TestOps 亮相 TICA❣️ AI TestOps 所实现的混合模型解决方案…

相关系数(皮尔逊pearson相关系数和斯皮尔曼spearman等级相关系数)

目录 总体皮尔逊Person相关系数&#xff1a; 样本皮尔逊Person相关系数&#xff1a; 两点总结&#xff1a; 假设检验&#xff1a;&#xff08;可结合概率论课本假设检验部分&#xff09; 皮尔逊相关系数假设检验&#xff1a; 更好的方法&#xff1a;p值判断方法 皮尔逊相…

lua调用c动态库实例

简介 Lua 是一种轻量小巧的脚本语言&#xff0c;用标准C语言编写并以源代码形式开放&#xff0c; 其设计目的是为了嵌入应用程序中&#xff0c;从而为应用程序提供灵活的扩展和定制功能。 特点 轻量级: 它用标准C语言编写并以源代码形式开放&#xff0c;编译后仅仅一百余K&a…

STM32/51单片机实训day4——RFID数据读取|RC522|串口数据收发、可模拟RFID (三) 仿真

目录 1 任务指导 2 实验步骤 3 串口调试 4 USART配置 5 fputs函数重写 内 容&#xff1a;能够读取RFID卡S50的ID——编程实现串口数据收发 学 时&#xff1a;3学时 知识点&#xff1a;电路图设计、USART配置 重点&#xff1a; USART配置 难点&#xff1a;USART配置 时…

赶快升级吧!PHP8比PHP5快41倍,比PHP7快3倍

本文得出的结论&#xff0c;归结于仅运行纯CPU任务的脚本的基准测试结果&#xff0c;不需要I/O操作的任务&#xff0c;例如访问文件、网络或数据库连接。 这些是纯 CPU 基准测试。它们并未涵盖 PHP 性能的所有方面&#xff0c;并且它们可能无法代表实际情况。然而&#xff0c;结…

用Python标准库统计CSDN阅读量

urllib基础 一般做爬虫其实很少有推荐urllib的&#xff0c;但urllib乃是Python标准库成员&#xff0c;在要求比较简单的情况下&#xff0c;采用urllib还是比较方便的。 作为爬虫入门必学包&#xff0c;urllib最常用的函数一定是urllib.request中的urlopen。其返回对象是HTTPR…

ES学习路程(二)

关于ES第一篇是在Linux安装&#xff0c;为了方便我在windows搭建一套ES和kibana版本&#xff08;7.15.0&#xff09; 第一步&#xff1a;下载安装ES在windows 官网下载相应版本的es和kibana&#xff1a; https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7…

《图解TCP/IP》阅读笔记(第八章 8.6、8.7)—— 网络管理与其他应用层协议

前言 本篇是第八章的最后一篇 8.6 网络管理 从前&#xff0c;网络管理凭借管理员的记忆和直觉进行&#xff0c;但是网络规模越大&#xff0c;人的力量就越不足&#xff0c;所以需要一个严密的管理工具或方法。 在TCP/IP的网络管理中&#xff0c;可以使用SNMP&#xff08;Si…

uni-app——小程序实现本地图片的上传以及身份证的智能识别

文章目录 前言一、示例图二、实现过程 1.完成提交图片的api地址2.获取本地图片3.将本地图片上传至开发者服务器三、具体实现代码四、身份证的智能识别总结前言 上传本地图片的功能很常见&#xff0c;那么具体该如何实现呢&#xff1f; 一、示例图 二、实现过程 1.完成提交图…

操作系统接口系统调用的实现

接口 连接两个东西&#xff0c;信号转换&#xff0c;屏蔽细节… 操作系统接口 连接上层用户和操作系统软件&#xff0c;方便了使用&#xff0c;屏蔽了细节。 操作系统接口的形式 为应用层提供一些重要的函数&#xff0c;如printf&#xff0c;write&#xff0c;read等。接口…