算法力扣刷题记录 五十六【501.二叉搜索树中的众数】

news2024/11/15 23:35:09

前言

二叉搜索树操作,继续。
记录 五十六【501.二叉搜索树中的众数】


一、题目阅读

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

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

假定 BST 满足如下定义:

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

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

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

示例 2:

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

提示:

树中节点的数目在范围 [1, 10^4] 内
-10^5 <= Node.val <= 10^5

进阶:你可以不使用额外的空间吗?(假设由递归产生的隐式调用栈的开销不被计算在内)


二、尝试实现

依然使用二叉搜索树中序遍历得到有序递增序列的特性。

思路【直白想法】

  1. 借助数组,通过中序遍历将二叉搜索树中的值取出来。再在数组中操作。
  2. 在数组中使用双指针循环,判断一个值出现的次数,再和最大次数记录比较:
  • 如果比最大出现次数的记录小,那么不操作;
  • 如果相等,那么加入到返回值数组中;
  • 如果比最大出现次数的记录大,判断返回值数组中是否为空,先清空后加入。

代码实现【借助数组,额外开辟空间】

/**
 * Definition for a binary tree node.
 * 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:
    void traversal(TreeNode* cur,vector<int>& nums){
        if(!cur) return;
        traversal(cur->left,nums);
        nums.push_back(cur->val);
        traversal(cur->right,nums);
        return;
    }
    vector<int> findMode(TreeNode* root) {
       vector<int> result;
       vector<int> nums;
       traversal(root,nums);
       int max = 0;
       for(int i = 0;i < nums.size();){
            int j=i+1;
            int count = 1;
            for(;j < nums.size();j++){
                if(nums[j] == nums[i]){
                    count++;
                }else{
                    break;
                }
            }
            if(count > max){
                if(!result.empty()) result.clear();
                result.push_back(nums[i]);
                max = count;
            }else if(count == max){
                result.push_back(nums[i]);
            }
            i = j;
       }
       return result;
    }
};

三、参考学习

参考学习链接

学习目标:如何在树中边遍历边确定众数?肯定还是双指针。尝试一下:有bug

class Solution {
public:
    int maxcount = 0;//记录最大次数
    int count = 1;//计数。
    TreeNode* pre =  nullptr;
    void traversal(TreeNode* cur,vector<int>& nums){
        if(!cur) return;
        traversal(cur->left,nums);
        if(pre && pre->val == cur->val){
            count++;
        }else if(pre && pre->val != cur->val){
            if(count > maxcount){
                if(!nums.empty()) nums.clear();
                nums.push_back(pre->val);
                maxcount = count;//最大值更新
            }else if(count == maxcount){
                nums.push_back(pre->val);
            }
            count = 1;//重新计数新的值
            pre = cur;//此处才更新pre
        }else if(!pre){
            pre = cur;//初始时,避免pre空
        }
        traversal(cur->right,nums);
        return;
    }
    vector<int> findMode(TreeNode* root) {
        vector<int> result;
        traversal(root,result);
        //处理最后
        

    }
};

使用时候,如何结束时也能操作元素呢?在cur->right后还有处理逻辑。

学习内容

  1. 双指针法解决:先说误区
  • 从借助数组的代码实现中发现遍历数组时,使用了i,j相当于i不动,j移动,统计这个元素出现次数。如果nums[j] != nums[i]说明nums[i]出现次数统计完毕。接下来比较count和max。
  • 没有想到可以相邻元素比较,如果相等,count++。count加一次,和max比较一次;不相等时,前面的count已经放到结果里。每一次都要进行count和max比较。
  • 尝试双指针错误在于,认为pre->val和cur->val不相等时,才更新pre,才比较count和max。正确:pre紧跟cur,把count和max的比较放到if外面,这样count更新,max更新。
  • 总结:错误——元素比较不相等时,统计完一个元素次数后放入结果;正确——每次元素比较,即使相等,也要判断count和max。
  1. 双指针代码修正
class Solution {
public:
    int maxcount = 0;//记录最大次数
    int count = 1;//计数。
    TreeNode* pre =  nullptr;
    void traversal(TreeNode* cur,vector<int>& nums){
        if(!cur) return;
        traversal(cur->left,nums);
        if(pre && pre->val == cur->val){
            count++;
        }else if(pre && pre->val != cur->val ){
            count = 1;//重新计数新的值
        }
        pre = cur;//初始时,避免pre空

        if(count > maxcount){
            if(!nums.empty()) nums.clear();
            nums.push_back(pre->val);
            maxcount = count;//最大值更新
        }else if(count == maxcount){
            nums.push_back(pre->val);
        }

        traversal(cur->right,nums);
        return;
    }
    vector<int> findMode(TreeNode* root) {
        vector<int> result;
        traversal(root,result);
        return result;
    }
};
  1. 迭代法:中序迭代模版,加中间节点处理逻辑。
  2. 普通二叉树如何求众数?
  • 普通二叉树数值没有任何关系,那么双指针法不成立。不过借助数组方法依然可以用。
  • 借助数组:遍历取出所有值放到vector里面,之后sort从小到大排个序,遍历数组;
  • 参考借助数组思路:用unordered_map统计元素出现次数,再把map转换成vector,再自定义比较函数,带入sort中,得到从大到小的排序vector。
  1. 普通二叉树求众数代码实现:
/**
 * Definition for a binary tree node.
 * 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:
    void traversal(TreeNode* cur,unordered_map<int,int>& nums){
        if(!cur) return;
        nums[cur->val]++;
        traversal(cur->left);
        traversal(cur->right);
    }
    bool cmp(const pair<int,int>& a,const pair<int,int>& b) const{
        return a.second > b.second;
    }
    vector<int> findMode(TreeNode* root) {
        vector<int> result;
        unordered_map<int,int> map;
        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 = 0;i <vec.size();i++){
            if(vec[i].second == vec[0].second) result.push_back(vec[i].first);
        }
        return result;
    }
};

总结

【501.二叉搜索树中的众数】和【求普通二叉树的众数】
在这里插入图片描述
(欢迎指正,转载标明出处)

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

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

相关文章

基于机器学习的二手房价格分析与预测设计与实现

概述 随着西安房地产市场的不断发展和变化&#xff0c;对二手房价格的准确预测变得至关重要。本研究旨在利用机器学习技术对西安市二手房价格进行深入分析与预测&#xff0c;通过对原始数据进行数据预处理和特征提取&#xff0c;以构建有效的预测模型。通过数据分析和可视化&a…

IP数据报结构详解:从基础到进阶

目录 IP数据报的格式 IP数据报首部的固定部分 IP数据报首部的可变部分 实例分析&#xff1a;数据报的分片 生存时间&#xff08;TTL&#xff09;与协议 首部检验和 总结 在网络通信中&#xff0c;IP数据报是至关重要的基本单元。本文将带您深入了解IP数据报的格式及其各个…

Java | Leetcode Java题解之第264题丑数II

题目&#xff1a; 题解&#xff1a; class Solution {public int nthUglyNumber(int n) {int[] dp new int[n 1];dp[1] 1;int p2 1, p3 1, p5 1;for (int i 2; i < n; i) {int num2 dp[p2] * 2, num3 dp[p3] * 3, num5 dp[p5] * 5;dp[i] Math.min(Math.min(num2…

C语言顺序表插入删除 尾删 任意删除 任意插入 链表头插

各位少年&#xff0c;大家好我是小敖 &#xff0c;今天给大家分享 顺序表的头删 尾删&#xff0c;任意删除&#xff0c;任意插入&#xff0c;链表头插。接下来跟大家分享。 头插的操作 c void SLPushFront(SL*psl, SLDatatype x) {SLCheckCapacity(psl); int end psl->siz…

stm32平台为例的软件模拟时间,代替RTC调试

stm32平台为例的软件模拟时间&#xff0c;代替RTC调试 我们在开发项目的时候&#xff0c;如果用到RTC&#xff0c;如果真正等待RTC到达指定的时间&#xff0c;那调试时间就太长了。 比如每隔半个小时&#xff0c;存储一次数据&#xff0c;如果要观察10次存储的效果&#xff0…

nginx通过nginx_upstream_check_module实现后端健康检查

1、简介说明 nginx是常用的反向代理和负载均衡服务&#xff0c;具有强大并发能力、稳定性、丰富的功能集、低资源的消耗。 nginx自身是没有针对后端节点健康检查的&#xff0c;但是可以通过默认自带的ngx_http_proxy_module 模块和ngx_http_upstream_module模块中的相关指令来完…

LDR6020双盲插便携显示器应用

随着USB Type-C接口的普及&#xff0c;越来越多的手机和笔记本电脑都支持通过C接口输出视频。这个小巧而精密的接口&#xff0c;大有把传统的HDMI和DisplayPort接口取而代之的架势。特别是usb4的推出&#xff0c;更是为USB TYPE-C接口一统有线接口形态奠定了基础。 单USB-C接口…

电子电器架构 - SOA架构软件平台

电子电器架构 - SOA架构软件平台 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无…

Django transaction.atomic()事务处理

在Django中&#xff0c;transaction.atomic()是一个上下文管理器&#xff0c;它会自动开始一个事务&#xff0c;并在代码块执行完毕后提交事务。如果在代码块中抛出异常&#xff0c;事务将被自动回滚&#xff0c;确保数据库的一致性和完整性。 在实际应用中&#xff0c;你可能需…

深入浅出WebRTC—ULPFEC

FEC 通过在发送端添加额外的冗余信息&#xff0c;使接收端即使在部分数据包丢失的情况下也能恢复原始数据&#xff0c;从而减轻网络丢包的影响。在 WebRTC 中&#xff0c;FEC 主要有两种实现方式&#xff1a;ULPFEC 和 FlexFEC&#xff0c;FlexFEC 是 ULPFEC 的扩展和升级&…

8.持久化

队列和消息都可以持久化。 持久化的目的就是让消息不丢失。 RabbitMQ本身退出&#xff0c;或者由于某种原因崩溃时造成的消息丢失。 RabbitMQ一旦宕机&#xff0c;就会造成队列和消息都丢失了。 RabbitMQ重启之后&#xff0c;非持久化的队列和消息都不存在了。 队列持久化…

项目部署--最原始的方法

服务器环境搭建 以腾讯云为例&#xff1a; 1.可以先用这个使用一个月的 2.访问服务器官网&#xff1a;腾讯云官网&#xff0c;进去先登录&#xff0c;再点击 控制台&#xff0c;找到 轻量应用服务器&#xff0c;进去之后会看见使用的服务器&#xff0c;有一个 公网IP&#xff…

[Spring Boot]Protobuf解析MQTT消息体

简述 本文主要针对在MQTT场景下&#xff0c;使用Protobuf协议解析MQTT的消息体 Protobuf下载 官方下载 https://github.com/protocolbuffers/protobuf/releases网盘下载 链接&#xff1a;https://pan.baidu.com/s/1Uz7CZuOSwa8VCDl-6r2xzw?pwdanan 提取码&#xff1a;an…

C语言:数组-学习笔记(万字笔记)——翻新版

目录 前言&#xff1a; 1、 数组的概念 1.1 什么是数组 1.2 为什么学习数组&#xff1f; 2. ⼀维数组的创建和初始化 2.1 数组创建 2.2 数组的初始化 2.3 数组的类型 2.3.1 什么是数组类型&#xff1f; 2.3.2 数组类型的作用 3、 一维数组的使用 3.1 数组下标 3.2 数…

ZYNQ 入门笔记(零):概述

文章目录 引言产品线Zynq™ 7000 SoCZynq UltraScale™ MPSoCZynq UltraScale RFSoCVersal™ Adaptive SoC 开发环境 引言 Xilinx FPGA 产品线从经济型的 Spartan、Artix 系列到高性能的 Kintex、Virtex、Versal 系列&#xff0c;可以说涵盖了 FPGA 的绝大部分应用场景&#x…

SpringBoot 最大连接数及最大并发数是多少

SpringBoot 最大连接数及最大并发数 Spring Boot 是一个基于 Spring 框架的快速开发框架&#xff0c;它本身并不直接管理数据库连接或网络连接的最大连接数和最大并发数。这些参数通常由底层的基础设施和组件来控制&#xff0c;例如&#xff1a; 数据库连接池&#xff1a;Spri…

Web 3.0革新:社交金融与边玩边赚开启用户数据主权时代

目录 Web 3.0与社交商业模式 传统社交平台的问题 去中心化社交创新 Mirror&#xff1a;去中心化内容发布平台 Lens Protocol&#xff1a;去中心化社交图谱 Maskbook&#xff1a;隐私保护的社交方式 Web 3.0与与边玩边赚模式 经济模型解析 新商业模式的探索 Axie Infi…

C++——模板初阶 | STL简介

P. S.&#xff1a;以下代码均在VS2019环境下测试&#xff0c;不代表所有编译器均可通过。 P. S.&#xff1a;测试代码均未展示头文件stdio.h的声明&#xff0c;使用时请自行添加。 博主主页&#xff1a;Yan. yan.                        …

maven私服上传jar包 400 Bad Request 错误

文章目录 前言一、直接看报错二、问题处理三 maven 私服配置说明总结 前言 maven仓库的私服,一般会存放公司或者个人封装的jar包,用来共享给二次开发和协作伙伴用,很方便 第一次发布没有问题,但是我第二次发布,开始报错了 一、直接看报错 [外链图片转存失败,源站可能有防盗链…

十五届蓝桥杯JAVA B组题目详解(持续更新中)

试题 B: 类斐波那契循环数 我发现蓝桥杯的题目现在就是要费时间去理解&#xff0c;所以还是审题很重要&#xff0c;这道题的思路就是&#xff0c;一个n位数的前n个数&#xff0c;都是对应的位数上的值&#xff0c;比如说12345&#xff0c;五位数是吧&#xff0c;那数列S的前五位…