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

前言

二叉搜索树操作,继续。
记录 五十六【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.mfbz.cn/a/843062.html

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

相关文章

【BUG】已解决:zipfile.BadZipFile: File is not a zip file

已解决&#xff1a;zipfile.BadZipFile: File is not a zip file 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开发…

IAR环境下STM32+IAP方案的实现

--基于STM32F103ZET6的UART通讯实现 一、什么是IAP&#xff0c;为什么要IAP IAP即为In Application Programming(在应用中编程)&#xff0c;一般情况下&#xff0c;以STM32F10x系列芯片为主控制器的设备在出厂时就已经使用J-Link仿真器将应用代码烧录了&#xff0c;如果在设备使…

Day16_集合与迭代器

Day16-集合 Day16 集合与迭代器1.1 集合的概念 集合继承图1.2 Collection接口1、添加元素2、删除元素3、查询与获取元素不过当我们实际使用都是使用的他的子类Arraylist&#xff01;&#xff01;&#xff01; 1.3 API演示1、演示添加2、演示删除3、演示查询与获取元素 2 Iterat…

ros笔记03--从零体验ros2话题通信方式

ros笔记03--从零体验ros2话题通信方式 介绍创建步骤体验官方 talker listener 案例基于python开发发布订阅案例 注意事项说明 介绍 主题是 ros2 提供的三种主要接口方式之一&#xff0c;它通常被用于连续的数据流&#xff0c;如传感器数据、机器人状态等。 ros2 是一个强类型的…

Artix7系列FPGA实现SDI视频编解码+UDP以太网传输,基于GTP高速接口,提供工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本博已有的以太网方案本博已有的FPGA图像缩放方案本方案的缩放应用本方案在Xilinx--Kintex系列FPGA上的应用本方案在Xilinx--Zynq系列FPGA上的应用 3、详细设计方案设计原理框图SDI 输入设备Gv8601a 均衡…

SAP Fiori 实战课程(二):新建页面

课程回顾 上一课中,利用Visual studio Code 新建、并运行了一个Demo工程。可以实现对项目的启动,启动后进入一个List清单。 那么本次课程的目前就是在上一节Demo的基础上,从零开始新建一个完整的页面。实现从首页清单,选择行后,鼠标点击,进入下一个页面。 准备工作 在开…

【20】读感 - 架构整洁之道(二)

概述 继上一篇文章讲了前两章的读感&#xff0c;已经归纳总结的重点&#xff0c;这章会继续跟进的看一下&#xff0c;深挖架构整洁之道。 编程范式 编程范式从早期到至今&#xff0c;提过哪些编程范式&#xff0c;结构化编程&#xff0c;面向对象编程&#xff0c;函数式编程…

想要获客如有神助攻,宝藏工具必不可少!

现如今&#xff0c;客户资源的收集和管理成为了一个让很多人都为之烦恼的问题。 然而&#xff0c;随着科技的进步&#xff0c;市场上出现了许多高效的宝藏工具&#xff0c;可以帮助你轻松解决这些问题&#xff0c;让获客如有神助攻&#xff01; 1、丰富的客户来源 无论是附近…

TypeScript体操(二):Utility Type手写实现

目录 前言常用 Utility Types 及其实现Partial<T>Required<T>Readonly<T>Pick<T, K>Omit<T, K>Record<K, T>Exclude<T, U>Extract<T, U>NonNullable<T>ReturnType<T>InstanceType<T>Parameters<T>Con…

synergy配置

今天介绍一个电脑同步软件synergy。 我们开发时一般会用两套设备&#xff0c;如果使用两套键盘操作起来会很麻烦&#xff0c;这个软件就是解决这个问题&#xff0c;可以使用一套键盘同时操作两台电脑&#xff0c;另一台作为客户端被控制。 安装 在两台电脑上各自下载安装syne…

沃文特过会两年仍在注册:营收净利润下滑,三次抽查不合格

《港湾商业观察》施子夫 王璐 在当前IPO严查之际&#xff0c;部分企业的上市进程可谓相当漫长&#xff0c;四川沃文特生物工程股份有限公司&#xff08;以下简称&#xff0c;沃文特&#xff09;就是其中之一。 不过&#xff0c;最近的好消息是&#xff0c;沃文特又更新了招股…

NVIDIA Container Toolkit 安装与配置帮助文档(Ubuntu,Docker)

NVIDIA Container Toolkit 安装与配置帮助文档(Ubuntu,Docker) 本文档详细介绍了在 Ubuntu Server 22.04 上使用 Docker 安装和配置 NVIDIA Container Toolkit 的过程。 概述 NVIDIA 容器工具包使用户能够构建和运行 GPU 加速容器。即可以在容器中使用NVIDIA显卡。 架构图如…

【BUG】已解决:TypeError: Descriptors cannot not be created directly.

已解决&#xff1a;TypeError: Descriptors cannot not be created directly. 目录 已解决&#xff1a;TypeError: Descriptors cannot not be created directly. 【常见模块错误】 【错误原因】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来…

谷粒商城实战笔记-46-商品服务-API-三级分类-配置网关路由与路径重写

文章目录 一&#xff0c;准备工作1&#xff0c;新增一级菜单2&#xff0c;新增二级菜单 二&#xff0c;前端树形界面开发1&#xff0c;开发分类展示组件 本节的主要内容&#xff1a; 前端调用三级分类接口&#xff0c;并树形展示 一&#xff0c;准备工作 启动product服务启动…

【开源库学习】libodb库学习(三)

4 查询数据库 如果我们不知道我们正在寻找的对象的标识符&#xff0c;我们可以使用查询在数据库中搜索符合特定条件的对象。ODB查询功能是可选的&#xff0c;我们需要使用--generate-query ODB编译器选项显式请求生成必要的数据库支持代码。 ODB提供了一个灵活的查询API&#x…

RPM、YUM 安装 xtrabackup 8 (mysql 热备系列一)包含rpm安装 mysql 8 配置主从

RPM安装 percona-xtrabackup-80-8.0.35-30.1.el7.x86_64.rpm 官网&#xff1a; https://www.percona.com/ 下载地址&#xff1a; https://www.percona.com/downloads wget https://downloads.percona.com/downloads/percona-distribution-mysql-ps/percona-distribution-mysq…

接口测试JMeter-1.接口测试初识

第一章 接口测试初识 1. 接口测试理论基础 “接口测试”一个让人觉得非常高大上的名词&#xff0c;特别是对于刚入门的测试同学而言。随着测试技术不断的深化&#xff0c;“接口测试”出现在我们视野中的频次越来越高。那么接口测试到底是如何做的&#xff1f;接口测试的优势又…

《简历宝典》17 - 简历中“技术能力”,如何丰满且有层次,前端篇

这一节开始对技术能力模块做讲解&#xff0c;我们身边的这些互联网IT从业者们&#xff0c;前端开发、Java开发、软件测试又或者是其他职位的开发者们&#xff0c;技术能力这个模块是绕不过去的&#xff0c;从简历上看&#xff0c;这个模块体现了我们之前软件工作生涯中的技术功…

解决:Linux上SVN 1.12版本以上无法直接存储明文密码

问题&#xff1a;今天在Linux机器上安装了SVN&#xff0c;作为客户端使用&#xff0c;首次执行SVN相关操作&#xff0c;输入账号密码信息后&#xff0c;后面再执行SVN相关操作&#xff08;比如"svn update"&#xff09;还是每次都需要输入密码。 回想以前在首次输入…

跨平台WPF音乐商店应用程序

目录 一 简介 二 设计思路 三 源码 一 简介 支持在线检索音乐&#xff0c;支持实时浏览当前收藏的音乐及音乐数据的持久化。 二 设计思路 采用MVVM架构&#xff0c;前后端分离&#xff0c;子界面弹出始终位于主界面的中心。 三 源码 视窗引导启动源码&#xff1a; namesp…