Leetcode:501. 二叉搜索树中的众数(C++)

news2024/11/17 6:55:43

目录

问题描述:

实现代码与解析:

通用写法(递归):

原理思路:

依据二叉搜索树特性写法(递归):

原理思路:

迭代:

原理思路:


问题描述:

        给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。

如果树中有不止一个众数,可以按 任意顺序 返回。

假定 BST 满足如下定义:

  • 结点左子树中所含节点的值 小于等于 当前节点的值
  • 结点右子树中所含节点的值 大于等于 当前节点的值
  • 左子树和右子树都是二叉搜索树

示例 1:

输入:root = [1,null,2,2]
输出:[2]

示例 2:

输入:root = [0]
输出:[0]

实现代码与解析:

通用写法(递归):

class Solution {
public:
    //遍历
    void traversal(TreeNode* cur,unordered_map<int,int>& map)
    {
        if(cur==NULL) return;
        map[cur->val]++;//对应值的频率加一
        traversal(cur->left,map);
        traversal(cur->right,map);
    }
    bool static cmp (const pair<int, int>& a, const pair<int, int>& b) 
    {
        return a.second > b.second;
    }
    vector<int> findMode(TreeNode* root) 
    {
        unordered_map<int,int> map;//<结点值,频率>
        vector<int> result;//结果
        traversal(root,map);
        vector<pair<int,int>> vec(map.begin(),map.end());
        sort(vec.begin(),vec.end(),cmp);//根据频率排序一下
        result.push_back(vec[0].first);
        for(int i=1;i<vec.size();i++)
        {
            if(vec[i].second==vec[0].second)
            {
                result.push_back(vec[i].first);
            }
            else
            {
                break;
            }
        }
        return result;
    }
};

原理思路:

        二叉树求众数的通用写法,非二叉搜索树也可以用。

        1、首先用map<结点值,频率>来接收遍历结果,

        2、然后再依据频率排序,由于map只能依据key来排序,不能依据value,所以我们这里先转化成vector<pair<int,int>>来进行排序。

        3、最后取出频率最大的一个值或多个值,放入result数组中。

下面介绍二叉搜索树的写法,当然二叉搜索树也可以用上面这种通用写法。

依据二叉搜索树特性写法(递归):

class Solution {
public:
    TreeNode* pre=NULL;//记录前一个结点
    int maxCount=0;//最大频率
    int count=0;//统计频率
    vector<int> vec;//记录众数,可能有多个,我们用数组记录
    void traversal(TreeNode* cur)
    {
        if(cur==NULL) return;
        traversal(cur->left);//左
        //第一个结点
        if(pre==NULL)
        {
            count=1;//更新当前频率
        }
        //若与前一结点值相同
        else if(pre->val==cur->val)
        {
            count++;
        }
        //与前一个结点值不同
        else
        {
            count=1;
        }
        //若当前频率等于最大频率
        if(count==maxCount)
        {
            vec.push_back(cur->val);//记录该结点值
        }
        //若当前频率大于最大频率
        else if(count>maxCount)
        {
            maxCount=count;//更新最大值
            vec.clear();//最大频率已经改变,凭空之前的记录值
            vec.push_back(cur->val);
        }
        pre=cur;//跟新前一结点
        traversal(cur->right);//右
    }
    vector<int> findMode(TreeNode* root) 
    {
        traversal(root);
        return vec;
    }
};

原理思路:

        和二叉搜索树一样,我们肯定还是在中序处理结点。

        1、首先我们要定义maxCount来记录最大频率,count来记录当前遍历结点值的频率,在过程中要不断更新,还要定义一个pre来记录前一个结点值,以及result数组来记录结果。

        2、中序处理:首先要获取当前count值,若pre为空,说明是第一个结点,直接令count=1即可。

        3、若pre不空,判断pre的值与当前结点值是否相等,若相等,count++,若不相等,依旧令count=1,我们就得到了当前count值。

        4、然后我们就要用count和maxCount做比较,若相等,说明此元素为当前遍历过的结点中的最大频率相同的众数,result记录其值,若count大于maxCount,说明此元素的频率超过了最大频率,我们清空result,将新的最大频率的值放入result数组中,清空result是容易忽略的点,大家要注意一下,result一定要清空,因为此时最大频率已经变了,之前记录的结果显然需要去除掉。

        5、最后别忘了,更新pre,记录结点,作为下一个结点的前一个结点。

        其实注释写的已经很具体了,大家可以结合注释看。

迭代:

class Solution {
public:
    vector<int> findMode(TreeNode* root) 
    {
        stack<TreeNode*> st;
        TreeNode* cur = root;
        TreeNode* pre = NULL;
        int maxCount = 0; // 最大频率
        int count = 0; // 当前频率
        vector<int> result;
        while (cur != NULL || !st.empty()) {
            if (cur != NULL) 
            { 
                st.push(cur); 
                cur = cur->left;                
            } 
            else 
            {
                cur = st.top();
                st.pop(); 
                // 第一个节点                     
                if (pre == NULL) 
                { 
                    count = 1;
                }
                // 与前一个节点数值相同 
                else if (pre->val == cur->val) 
                { 
                    count++;
                } 
                // 与前一个节点数值不同
                else 
                { 
                    count = 1;
                }
                if (count == maxCount) 
                { 
                    result.push_back(cur->val);
                }
                if (count > maxCount) 
                { 
                    maxCount = count;   // 更新最大频率
                    result.clear();     // 清空result
                    result.push_back(cur->val);
                }
                pre = cur;
                cur = cur->right;               
            }
        }
        return result;
    }
};

原理思路:

        中序迭代遍历,没什么可说的,和递归原理相同。

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

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

相关文章

Android Compose——一个简单的新闻APP

Owl简述效果视频导航导航结点路线图底部导航栏使用标签页状态切换FeaturePage构建CoursePage实现搜索ViewModelView详情页DetailDescribeLesson尾Gitte简述 此Demo是参考Google Github其中一个Demo而完成&#xff0c;涉及的内容并不复杂&#xff0c;主要是为了熟悉Compose编码…

2022爱分析・出海数字化系列报告之“出海实时互动与通信”厂商全景报告 | 爱分析报告

报告编委 张扬 爱分析联合创始人&首席分析师 文鸿伟 爱分析高级分析师 王鹏 爱分析分析师 目录 研究范围定义厂商全景地图市场分析与厂商评估入选厂商列表研究范围定义 研究范围 改革开放四十多年来&#xff0c;中国企业经历了自商品出海到当前的品牌出海&#xff0c;出海…

Servlet的使用

作者&#xff1a;~小明学编程 文章专栏&#xff1a;JavaEE 格言&#xff1a;热爱编程的&#xff0c;终将被编程所厚爱。 目录 什么是Servlet&#xff1f; 创建一个Servlet程序 1.创建一个Maven项目 2.引入依赖 3.创建目录 4.编写代码 5.打包 6.部署程序 7.验证程序 …

Rust如何进行模块化开发?

类似es6的模块化&#xff0c;Rust通过package、create、module来实现代码的模块化管理 Rust如何进行模块化开发&#xff1f; Rust的代码组织包括&#xff1a;哪些细节可以暴露&#xff0c;哪些细节是私有的&#xff0c;作用域内哪些名称有效等等。 而这些功能被统称为模块系统…

晒成绩单了,百度智能云交出2022年终大考试卷!

晒成绩单了&#xff0c;百度智能云交出2022年终大考试卷&#xff01; 2023年伊始&#xff0c;工厂加快步伐复工复产、城市烟火气涌现、消费活力加速释放&#xff0c;企业对未来发展呈现乐观预期。有外媒称&#xff0c;“中国经济将实现比预期更快的复苏””。 站在更宏观的视…

java入门到废为止

目录基础数据变量类型数据类型基本类型上下转型引用类型类型对比装箱拆箱缓存池输入数据数组初始化元素访问内存分配数组异常二维数组运算参数形参实参可变参数方法方法概述定义调用注意事项方法重载重载介绍方法选取继承重载参数传递枚举Debug对象概述类定义构造器包封装thiss…

【React】二.JSX

目录 二.JSX JSX的基本使用 jsx使用步骤 JSX中使用JavaScript表达式 嵌入JS表达式 注意点 JSX的条件渲染 问题记录 JSX的列表渲染 JSX的样式处理 总结 二.JSX JSX的基本使用 createElement()的问题繁琐不简洁不能直观看出所描述的结构不优雅&#xff0c;用户体验不佳…

Java设计模式-代理模式Proxy

介绍 代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问&#xff0c;这样就可以在不修改原目标对象的前提下&#xff0c;提供额外的功能操作&#xff0c;扩展目标对象的功能。 代理模式的主要作用是扩展目标对象的功能&a…

Linux编译器-gcc/g++的使用

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;Linux &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 本博客主要内容主要介绍了Linux编译器g/gcc的相关使用方法&#xff0c…

Linux学习笔记——分布式内存计算Flink环境部署

5.13、分布式内存计算Flink环境部署 5.13.1、简介 Flink同Spark一样&#xff0c;是一款分布式内存计算引擎&#xff0c;可以支撑海量数据的分布式计算。 Flink在大数据体系同样是明星产品&#xff0c;作为最新一代的综合计算引擎&#xff0c;支持离线计算和实时计算。 在大…

libcurl库及curl API的简介

目录 一、libcurl简介 二、curl API简介 三.库安装编译方法 内容来源&#xff1a;Http协议之libcurl实现 - 谢呈勖 - 博客园 (cnblogs.com) 一、libcurl简介 libcurl是一个跨平台的网络协议库&#xff0c;支持http, https, ftp, gopher, telnet, dict, file, 和ldap 协议。…

当 Rainbond 遇上龙蜥!小龙带你玩转一站式云原生,点击开启

Rainbond 是一个云原生应用管理平台&#xff0c;使用简单&#xff0c;不需要懂容器、Kubernetes 和底层复杂技术&#xff0c;支持管理多个 Kubernetes 集群&#xff0c;和管理企业应用全生命周期。主要功能包括应用开发环境、应用市场、微服务架构、应用交付、应用运维、应用级…

Golang的Fork/Join实现

做过Java开发的同学肯定知道&#xff0c;JDK7加入的Fork/Join是一个非常优秀的设计&#xff0c;到了JDK8&#xff0c;又结合并行流中进行了优化和增强&#xff0c;是一个非常好的工具。1、Fork/Join是什么Fork/Join本质上是一种任务分解&#xff0c;即&#xff1a;将一个很大的…

FPGA图像处理HLS实现RGB转灰度,提供HLS工程和vivado工程源码

目录一、图像RGB转灰度原理二、HLS方案实现三、HLS在线仿真并导出IP四、Kintex7开发板vivado工程验证五、zynq7100开发板vivado工程验证六、板级调试验证七、福利&#xff1a;工程源码获取一、图像RGB转灰度原理 图像rgb转灰度图有固定的公式&#xff0c;具体公式csdn一大堆&a…

mirco:bit是什么?小学生拿着它就能召唤神龙?

mirco:bit是什么&#xff1f;micro:bit是一款由英国广播电视公司(BBC) 为青少年编程教育设计&#xff0c;并由微软&#xff0c;三星&#xff0c;ARM&#xff0c;英国兰卡斯特大学等合作伙伴共同完成开发的微型电脑。BBC希望通过micro:bit驱动青少年参与到创造性的硬件制作和软件…

MySQL基础——DCL语句

概述 DCL(Data Control Language)语句&#xff1a;数据控制语句&#xff0c;用于控制不同数据段直接的许可和访问级别的语句。这些语句定义了数据库、表、字段、用户的访问权限和安全级别。 管理用户 查询 查询用户代码如下&#xff1a; USE mysql; SELECT * FROM user; …

ASEMI桥式整流器KBU808的优缺点

编辑-Z 型号&#xff1a;KBU808 最大重复峰值反向电压&#xff08;VRRM&#xff09;&#xff1a;800V 最大RMS电桥输入电压&#xff08;VRMS&#xff09;&#xff1a;560V 最大直流阻断电压&#xff08;VDC&#xff09;&#xff1a;800V 最大平均正向整流输出电流&#xf…

3D视觉技术登上火星?NASA也用上了NeRF技术做太空勘探

原文链接&#xff1a;https://www.techbeat.net/article-info?id4468 作者&#xff1a;seven_ 现阶段&#xff0c;人类探索宇宙的一个关键方向是如何高效的利用航天器返回的数据来了解和分析外太空的环境特点。其中最为常用的就是图像数据&#xff0c;但是这些数据非常宝贵&am…

C语言-自定义类型-结构体应用-通讯录(11.2)

目录 1.通讯录的设计思路 1.1主函数与通讯录框架 1.2菜单的实现 1.3通讯录的定义与初始化 2.通讯录具体功能的实现 2.1添加联系人 2.2删除联系人 2.3查找联系人 2.4修改联系人信息 2.5整理通讯录&#xff08;按年龄排序&#xff09; 2.6查看整个通讯录 3.通讯录源码…

Ubuntu 网络管理

一&#xff1a;NetPlan配置 1、安装netplan 如果/etc/netplan目录不存在请用以下命令安装&#xff1a; apt -y install netplan.io 2、配置文件 创建并编辑/etc/netplan/01-netplan.yaml文件&#xff1a; eth0&#xff1a;动态分配&#xff1b;eth1&#xff1a;静态分配 …