二叉搜索树题目:二叉搜索树中的众数

news2024/9/30 17:28:35

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
      • 进阶
  • 解法一
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法二
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法三
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:二叉搜索树中的众数

出处:501. 二叉搜索树中的众数

难度

3 级

题目描述

要求

给定一个含重复值的二叉搜索树的根结点 root \texttt{root} root,返回二叉搜索树中的所有众数(即出现频率最高的元素)。

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

假定二叉搜索树满足如下定义:

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

示例

示例 1:

示例 1

输入: root   =   [1,null,2,2] \texttt{root = [1,null,2,2]} root = [1,null,2,2]
输出: [2] \texttt{[2]} [2]

示例 2:

输入: root   =   [0] \texttt{root = [0]} root = [0]
输出: [0] \texttt{[0]} [0]

数据范围

  • 树中结点数目在范围 [1,   10 4 ] \texttt{[1, 10}^\texttt{4}\texttt{]} [1, 104]
  • -10 5 ≤ Node.val ≤ 10 5 \texttt{-10}^\texttt{5} \le \texttt{Node.val} \le \texttt{10}^\texttt{5} -105Node.val105

进阶

你可以使用常数额外空间吗?

解法一

思路和算法

由于二叉搜索树的中序遍历序列是单调递增的,因此二叉搜素树的中序遍历序列中的相同结点值一定相邻。只要得到二叉搜索树的中序遍历序列,即可得到每个结点值的出现次数,并得到众数。

使用递归实现中序遍历的做法是依次访问左子树、根结点和右子树,对于左子树和右子树使用同样的方法访问。

由于中序遍历序列中的相同结点值一定相邻,因此不需要存储完整的中序遍历序列,而是只需要存储上一个遍历到的结点值和出现次数。每次访问结点时,判断当前结点值和上一个结点值是否相等,更新当前结点值的出现次数,然后比较当前结点值的出现次数与最大出现次数,维护二叉搜索树中的众数。

  • 如果当前结点值的出现次数等于最大出现次数,则将当前结点值添加到众数列表中。

  • 如果当前结点值的出现次数大于最大出现次数,则将最大出现次数更新为当前结点值的出现次数,将众数列表清空后将当前结点值添加到众数列表中。

遍历结束之后,众数列表中的结点值即为二叉搜索树中的全部众数。

对于中序遍历序列中的任意两个相邻结点值,或者结点值不同,或者结点值相同且出现次数不同,因此同一个结点值最多在众数列表中出现一次,不会重复出现。

代码

class Solution {
    int prev;
    int freq;
    int maxFreq;
    List<Integer> modesList;

    public int[] findMode(TreeNode root) {
        prev = Integer.MIN_VALUE;
        freq = 0;
        maxFreq = 0;
        modesList = new ArrayList<Integer>();
        inorder(root);
        int size = modesList.size();
        int[] modes = new int[size];
        for (int i = 0; i < size; i++) {
            modes[i] = modesList.get(i);
        }
        return modes;
    }

    public void inorder(TreeNode node) {
        if (node == null) {
            return;
        }
        inorder(node.left);
        if (node.val == prev) {
            freq++;
        } else {
            prev = node.val;
            freq = 1;
        }
        if (freq == maxFreq) {
            modesList.add(node.val);
        } else if (freq > maxFreq) {
            maxFreq = freq;
            modesList.clear();
            modesList.add(node.val);
        }
        inorder(node.right);
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉搜索树的结点数。每个结点都被访问一次。

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉搜索树的结点数。空间复杂度主要是递归调用的栈空间,取决于二叉搜索树的高度,最坏情况下二叉搜索树的高度是 O ( n ) O(n) O(n)

解法二

思路和算法

使用迭代实现二叉搜索树的中序遍历的做法是使用栈存储结点。

每次访问结点时,需要判断当前结点值和上一个结点值是否相等,根据结点值和出现次数维护二叉搜索树中的众数。

代码

class Solution {
    public int[] findMode(TreeNode root) {
        int prev = Integer.MIN_VALUE;
        int freq = 0;
        int maxFreq = 0;
        List<Integer> modesList = new ArrayList<Integer>();
        Deque<TreeNode> stack = new ArrayDeque<TreeNode>();
        TreeNode node = root;
        while (!stack.isEmpty() || node != null) {
            while (node != null) {
                stack.push(node);
                node = node.left;
            }
            node = stack.pop();
            if (node.val == prev) {
                freq++;
            } else {
                prev = node.val;
                freq = 1;
            }
            if (freq == maxFreq) {
                modesList.add(node.val);
            } else if (freq > maxFreq) {
                maxFreq = freq;
                modesList.clear();
                modesList.add(node.val);
            }
            node = node.right;
        }
        int size = modesList.size();
        int[] modes = new int[size];
        for (int i = 0; i < size; i++) {
            modes[i] = modesList.get(i);
        }
        return modes;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉搜索树的结点数。每个结点最多被访问一次。

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉搜索树的结点数。空间复杂度主要是栈空间,取决于二叉搜索树的高度,最坏情况下二叉搜索树的高度是 O ( n ) O(n) O(n)

解法三

思路和算法

解法一和解法二都需要使用栈空间。为了将空间复杂度降低到常数,需要使用莫里斯遍历。

使用莫里斯遍历对二叉搜索树中序遍历时,同样在每次访问结点时判断当前结点值和上一个结点值是否相等,根据结点值和出现次数维护二叉搜索树中的众数。

由于事先无法知道众数的个数,因此需要用众数列表存储全部的众数,最后将众数列表转换成数组。Java 中的数组和列表是两种不同的类型,因此无法做到严格的常数空间复杂度。如果将众数列表看成返回值,则空间复杂度可以视为常数。

代码

class Solution {
    public int[] findMode(TreeNode root) {
        int prev = Integer.MIN_VALUE;
        int freq = 0;
        int maxFreq = 0;
        List<Integer> modesList = new ArrayList<Integer>();
        TreeNode node = root;
        while (node != null) {
            int curr = Integer.MIN_VALUE;
            if (node.left == null) {
                curr = node.val;
                node = node.right;
            } else {
                TreeNode predecessor = node.left;
                while (predecessor.right != null && predecessor.right != node) {
                    predecessor = predecessor.right;
                }
                if (predecessor.right == null) {
                    predecessor.right = node;
                    node = node.left;
                } else {
                    predecessor.right = null;
                    curr = node.val;
                    node = node.right;
                }
            }
            if (curr != Integer.MIN_VALUE) {
                if (curr == prev) {
                    freq++;
                } else {
                    prev = curr;
                    freq = 1;
                }
                if (freq == maxFreq) {
                    modesList.add(curr);
                } else if (freq > maxFreq) {
                    maxFreq = freq;
                    modesList.clear();
                    modesList.add(curr);
                }
            }
        }
        int size = modesList.size();
        int[] modes = new int[size];
        for (int i = 0; i < size; i++) {
            modes[i] = modesList.get(i);
        }
        return modes;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉搜索树的结点数。使用莫里斯遍历,每个结点最多被访问两次。

  • 空间复杂度: O ( 1 ) O(1) O(1)。不考虑返回值以及与返回值相关的临时空间时,空间复杂度是 O ( 1 ) O(1) O(1)

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

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

相关文章

峰值检测电路

常用的峰值检测电路&#xff0c;如下图所示。 该电路有两种工作状态&#xff1a; 1、充电状态&#xff1a;D2导通&#xff0c;D1截止。 当U1的端比-端大时&#xff0c;V1VIN&#xff0c;VCV1-VD2&#xff0c;VOUTVC。这时&#xff0c;给电容C1充电。由于D1截止没有环路&#…

Shell脚本介绍及脚本功能

文章目录 一、什么是shell二、hello word2.1 echo2.2第一个脚本 三、Bash的基本功能3.1别名3.2常用快捷键3.3输入输出3.4 输出重定向3.5 多命令执行3.6 管道符3.7 通配符和特殊符号 一、什么是shell Shell 是一个用 C 语言编写的程序&#xff0c;它是用户使用 Linux 的桥梁。S…

背包问题(介绍+例题+代码+注解)

目录 介绍&#xff1a; 一、01背包 题目描述 输入描述: 输出描述: 代码&#xff1a; 二、完全背包 题目描述 输入描述: 输出描述: 代码&#xff1a; 三、多重背包 题目描述 输入描述: 输出描述: 代码&#xff1a; 四、背包问题 题目描述 输入描述: 输出描…

Mybatis2

Mybatis2 本章目标&#xff1a; myBatis类型别名处理 myBatis参数处理 myBatis结果集类型 myBatis结果集列名和属性名称对应方式处理 附录 本章内容 一、类型别名&#xff08;typeAliases&#xff09;处理 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置…

使用EFCore连接SQLite

简介 在使用EFCore连接SQLite之前我们先来了解一下SQLite SQLite是一个轻量级、自包含、无服务器、零配置的事务性SQL数据库引擎&#xff0c;它支持SQL92标准的大多数查询语言并兼容ACID事务。具体如下&#xff1a; 轻量级&#xff1a;SQLite非常轻巧&#xff0c;它的库体积…

[算法沉淀记录] 排序算法 —— 堆排序

排序算法 —— 堆排序 算法基础介绍 堆排序&#xff08;Heap Sort&#xff09;是一种基于比较的排序算法&#xff0c;它利用堆这种数据结构来实现排序。堆是一种特殊的完全二叉树&#xff0c;其中每个节点的值都必须大于或等于&#xff08;最大堆&#xff09;或小于或等于&am…

Huggingface学习笔记

课程地址&#xff1a;【HuggingFace简明教程,BERT中文模型实战示例.NLP预训练模型,Transformers类库,datasets类库快速入门.】 什么是huggingface&#xff1f; huggingface是一个开源社区&#xff0c;提供了先进的NLP模型、数据集以及工具。 主要模型&#xff1a; 安装环境&…

Rust升级慢,使用国内镜像进行加速

背景 rustup 是 Rust 官方的跨平台 Rust 安装工具&#xff0c;国内用户使用rustup update的时候&#xff0c;网速非常慢&#xff0c;可以使用国内的阿里云镜像源来进行加速 0x01 配置方法 1. Linux与Mac OS用户配置环境变量 修改~/.bash_profile文件添加如下内容&#xff1…

Docker基础篇(六) dockerfile体系结构语法

FROM&#xff1a;基础镜像&#xff0c;当前新镜像是基于哪个镜像的 MAINTAINER &#xff1a;镜像维护者的姓名和邮箱地址 RUN&#xff1a;容器构建时需要运行的命令 EXPOSE &#xff1a;当前容器对外暴露出的端口号 WORKDIR&#xff1a;指定在创建容器后&#xff0c;终端默认登…

lv21 QT入门与基础控件 1

1 QT简介 QT是挪威Trolltech开发的多平台C图形用户界面应用程序框架 典型应用 2 工程搭建 2.1 新建ui工程 不要写中文路径 2.1 不勾选UI&#xff08;主讲&#xff09; 3 QT信号与槽机制 语法&#xff1a;Connect&#xff08;A, SIGNLA(aaa()), B, SLOT(bbb())&#xff09;…

算法--贪心

这里写目录标题 区间问题区间选点引入算法思想例题代码 最大不相交区间的数量算法思想例题代码 区间分组算法思想例题代码 一级目录二级目录二级目录二级目录 区间问题 区间选点 引入 区间问题会给定几个区间&#xff0c;之后要求我们在数轴上选取尽量少的点&#xff0c;使得…

电脑休眠之后唤不醒

现象&#xff1a;午休时间电脑休眠了&#xff0c;醒来之后发现在密码输入界面&#xff0c;但鼠标键盘没反应。按重启键或电源机重新开机&#xff0c;结果开不了机。 原因&#xff1a;1、内存条脏了&#xff0c;导致内存条读取失败 2、休眠的时候硬盘休眠了&#xff0c;导致按…

欢迎免费申报讯方技术HarmonyOS人才训练营!

在今年1月备受瞩目的鸿蒙生态千帆启航仪式上&#xff0c;华为宣布&#xff1a;HarmonyOS NEXT星河预览版正式面向开发者开放申请&#xff0c;意味着鸿蒙将建立更广泛的生态系统&#xff0c;迎来更多的应用和软硬件产品&#xff0c;加速自我技术迭代&#xff0c;同时推动华为全场…

变革中的容器技术

容器化技术的优点 容器化是一种将应用程序和其所需的依赖项&#xff0c;封装在一个可在任何基础架构上一致运行的轻量级可执行文件&#xff08;即容器&#xff09;的技术。容器化技术可以大大简化应用程序的部署、管理和维护&#xff0c;提高运维效率和可靠性。 容器化技术有…

LeetCode_Java_动态规划(2)(题目+思路+代码)

131.分割回文串 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是 回文串 。返回 s 所有可能的分割方案。 回文串 是正着读和反着读都一样的字符串。 示例 1&#xff1a; 输入&#xff1a;s "aab" 输出&#xff1a;[["a&qu…

工具篇-- 定时任务xxl-job的集群部署

文章目录 前言一、xxl-job-admin 集群部署&#xff1a;1.1 部署步骤&#xff1a;1.2 部署求和建议&#xff1a;1.3 集群部署模拟&#xff08;单机&#xff09;&#xff1a; 二、xxl-job 执行器 集群部署&#xff1a;2.1 集群部署要求&#xff1a;2.2 集群部署模拟&#xff1a; …

pthread_exit和pehread_join函数

pthread_exit&#xff1a; 在线程中禁止调用exit函数&#xff0c;否则会导致整个进程退出&#xff0c;取而代之的是调用pthread_exit函数&#xff0c;这个函数只会使一个线程退出&#xff0c;如果主线程使用pthread_exit函数也不会使整个进程退出&#xff0c;不会影响其他线程…

【基础知识】MPP架构和hadoop架构比对

架构比对 简单一句描述。 mpp架构&#xff0c;就是找一群和自己能力差不多的任一起做事&#xff0c;每个人做的事情是一致的。 hadoop架构&#xff0c;就是找一群能力差一些的人&#xff0c;但只需要他们每个人只做一部分工作。 举例说明 一个特色小饭店如何成为连锁餐饮巨…

【国密算法】深入理解国密算法:原理、实践及注意事项

目录 引言 1. 国密算法概述 2. 国密算法的实践应用 2.1 对称加密&#xff08;SM1算法&#xff09; 2.2 非对称加密&#xff08;SM2算法&#xff09; 2.3 哈希算法&#xff08;SM3算法&#xff09; 3. 国密算法的注意事项 结论 引言 国密算法&#xff0c;即中国密码算法…

AI数字人SadTalker实战

1.概述 AI数字人在营销和品牌推广中扮演着至关重要的角色&#xff0c;许多企业和个人正积极利用数字技术来打造属于自己的财富。有没有一种简单而免费的方式来创建自己的数字人呢&#xff1f;本篇博客笔者将为大家介绍如何搭建属于自己的AI数字人。 2.内容 2.1 什么是SadTalker…