排序题目:多数元素 II

文章目录

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

题目

标题和出处

标题:多数元素 II

出处:229. 多数元素 II

难度

3 级

题目描述

要求

给定大小为 n \texttt{n} n 的数组 nums \texttt{nums} nums,找出其中所有出现超过 ⌊ n 3 ⌋ \Big\lfloor \dfrac{\texttt{n}}{\texttt{3}} \Big\rfloor 3n 次的元素。

示例

示例 1:

输入: nums   =   [3,2,3] \texttt{nums = [3,2,3]} nums = [3,2,3]
输出: [3] \texttt{[3]} [3]

示例 2:

输入: nums   =   [1] \texttt{nums = [1]} nums = [1]
输出: [1] \texttt{[1]} [1]

示例 3:

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

数据范围

  • n = nums.length \texttt{n} = \texttt{nums.length} n=nums.length
  • 1 ≤ n ≤ 5 × 10 4 \texttt{1} \le \texttt{n} \le \texttt{5} \times \texttt{10}^\texttt{4} 1n5×104
  • -10 9 ≤ nums[i] ≤ 10 9 \texttt{-10}^\texttt{9} \le \texttt{nums[i]} \le \texttt{10}^\texttt{9} -109nums[i]109

进阶

你可以使用线性时间复杂度和 O(1) \texttt{O(1)} O(1) 空间复杂度解决此问题吗?

前言

这道题是「多数元素」的进阶,要求找出数组中所有出现次数大于 ⌊ n 3 ⌋ \Big\lfloor \dfrac{n}{3} \Big\rfloor 3n 的元素。这道题也可以使用哈希表计数、排序和摩尔投票三种解法得到答案。

长度是 n n n 的数组中,最多有 2 2 2 个出现次数大于 ⌊ n 3 ⌋ \Big\lfloor \dfrac{n}{3} \Big\rfloor 3n 的元素。可以使用反证法证明。

假设有 3 3 3 个出现次数大于 ⌊ n 3 ⌋ \Big\lfloor \dfrac{n}{3} \Big\rfloor 3n 的元素,这 3 3 3 个元素的出现次数都不小于 ⌊ n 3 ⌋ + 1 \Big\lfloor \dfrac{n}{3} \Big\rfloor + 1 3n+1,因此这 3 3 3 个元素的总出现次数至少为 3 × ⌊ n 3 ⌋ + 3 3 \times \Big\lfloor \dfrac{n}{3} \Big\rfloor + 3 3×3n+3。由于 ⌊ n 3 ⌋ > n 3 − 1 \Big\lfloor \dfrac{n}{3} \Big\rfloor > \dfrac{n}{3} - 1 3n>3n1,因此 3 × ⌊ n 3 ⌋ + 3 > 3 × ( n 3 − 1 ) + 3 = 3 × n 3 − 3 + 3 = n 3 \times \Big\lfloor \dfrac{n}{3} \Big\rfloor + 3 > 3 \times (\dfrac{n}{3} - 1) + 3 = 3 \times \dfrac{n}{3} - 3 + 3 = n 3×3n+3>3×(3n1)+3=3×3n3+3=n,即这 3 3 3 个元素的总出现次数一定超过 n n n,和数组长度是 n n n 矛盾。因此数组中不可能有 3 3 3 个出现次数大于 ⌊ n 3 ⌋ \Big\lfloor \dfrac{n}{3} \Big\rfloor 3n 的元素,最多有 2 2 2 个出现次数大于 ⌊ n 3 ⌋ \Big\lfloor \dfrac{n}{3} \Big\rfloor 3n 的元素。

解法一

思路和算法

最直观的解法是统计数组中每个元素的出现次数,然后寻找出现次数大于 ⌊ n 3 ⌋ \Big\lfloor \dfrac{n}{3} \Big\rfloor 3n 的元素。

遍历数组,使用哈希表记录每个元素的出现次数,遍历结束之后即可得到数组中每个元素的出现次数。然后遍历哈希表,对于哈希表中的每个元素得到出现次数,将出现次数大于 ⌊ n 3 ⌋ \Big\lfloor \dfrac{n}{3} \Big\rfloor 3n 的元素添加到结果中。

代码

class Solution {
    public List<Integer> majorityElement(int[] nums) {
        Map<Integer, Integer> counts = new HashMap<Integer, Integer>();
        for (int num : nums) {
            counts.put(num, counts.getOrDefault(num, 0) + 1);
        }
        List<Integer> majorities = new ArrayList<Integer>();
        int n = nums.length;
        Set<Integer> set = counts.keySet();
        for (int num : set) {
            if (counts.get(num) > n / 3) {
                majorities.add(num);
            }
        }
        return majorities;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。遍历数组统计每个元素的出现次数需要 O ( n ) O(n) O(n) 的时间,遍历哈希表得到多数元素也需要 O ( n ) O(n) O(n) 的时间。

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。需要创建哈希表记录每个元素的出现次数,哈希表中的元素个数不超过 n n n

解法二

思路和算法

首先将数组排序,排序后的数组满足相等的元素一定出现在数组中的相邻位置。如果一个元素在数组中的出现次数大于 ⌊ n 3 ⌋ \Big\lfloor \dfrac{n}{3} \Big\rfloor 3n,则排序后的数组中存在至少 ⌊ n 3 ⌋ + 1 \Big\lfloor \dfrac{n}{3} \Big\rfloor + 1 3n+1 个连续的元素都等于该元素,即一定存在两个差为 ⌊ n 3 ⌋ \Big\lfloor \dfrac{n}{3} \Big\rfloor 3n 的下标处的元素都等于该元素。

将数组 nums \textit{nums} nums 排序之后遍历数组 nums \textit{nums} nums,对于下标 i i i,当 i ≥ ⌊ n 3 ⌋ i \ge \Big\lfloor \dfrac{n}{3} \Big\rfloor i3n 时,如果 nums [ i ] = nums [ i − ⌊ n 3 ⌋ ] \textit{nums}[i] = \textit{nums}[i - \Big\lfloor \dfrac{n}{3} \Big\rfloor] nums[i]=nums[i3n],则 nums [ i ] \textit{nums}[i] nums[i] 是出现次数大于 ⌊ n 3 ⌋ \Big\lfloor \dfrac{n}{3} \Big\rfloor 3n 的元素。

为了避免重复计算,当 i < n − 1 i < n - 1 i<n1 nums [ i ] = nums [ i + 1 ] \textit{nums}[i] = \textit{nums}[i + 1] nums[i]=nums[i+1] 时跳过下标 i i i,只有当下标 i i i 的右侧没有与 nums [ i ] \textit{nums}[i] nums[i] 相等的元素时才判断 nums [ i ] = nums [ i − ⌊ n 3 ⌋ ] \textit{nums}[i] = \textit{nums}[i - \Big\lfloor \dfrac{n}{3} \Big\rfloor] nums[i]=nums[i3n] 是否成立,如果成立则将 nums [ i ] \textit{nums}[i] nums[i] 添加到结果中。

代码

class Solution {
    public List<Integer> majorityElement(int[] nums) {
        Arrays.sort(nums);
        List<Integer> majorities = new ArrayList<Integer>();
        int n = nums.length;
        for (int i = n / 3; i < n; i++) {
            int num = nums[i];
            if (i < n - 1 && num == nums[i + 1]) {
                continue;
            }
            if (num == nums[i - n / 3]) {
                majorities.add(num);
            }
        }
        return majorities;
    }
}

复杂度分析

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n 是数组 nums \textit{nums} nums 的长度。排序需要 O ( n log ⁡ n ) O(n \log n) O(nlogn) 的时间。

  • 空间复杂度: O ( log ⁡ n ) O(\log n) O(logn),其中 n n n 是数组 nums \textit{nums} nums 的长度。排序需要 O ( log ⁡ n ) O(\log n) O(logn) 的递归调用栈空间。

解法三

思路和算法

原始的摩尔投票算法用于找到出现次数大于一半的元素,其时间复杂度是 O ( n ) O(n) O(n),空间复杂度是 O ( 1 ) O(1) O(1)。摩尔投票算法可以推广到寻找出现次数大于 ⌊ n k ⌋ \Big\lfloor \dfrac{n}{k} \Big\rfloor kn 的元素,其中 k k k 是大于 1 1 1 的正整数。

由于出现次数大于 ⌊ n 3 ⌋ \Big\lfloor \dfrac{n}{3} \Big\rfloor 3n 的元素不可能超过 2 2 2 个,因此维护 2 2 2 个候选元素 majority 1 \textit{majority}_1 majority1 majority 2 \textit{majority}_2 majority2,以及两个候选元素的出现次数 count 1 \textit{count}_1 count1 count 2 \textit{count}_2 count2,初始时候选元素和出现次数都是 0 0 0

遍历数组,当遍历到元素 num \textit{num} num 时,执行如下操作。

  1. 比较 num \textit{num} num 是否和候选元素相等,如果相等则将相应的出现次数加 1 1 1

    1. 如果 num = majority 1 \textit{num} = \textit{majority}_1 num=majority1,则将 count 1 \textit{count}_1 count1 1 1 1

    2. 否则,如果 num = majority 2 \textit{num} = \textit{majority}_2 num=majority2,则将 count 2 \textit{count}_2 count2 1 1 1

  2. 如果 num \textit{num} num 和两个候选元素都不相等,则判断两个候选元素的出现次数是否为 0 0 0,如果为 0 0 0 则更新候选元素和出现次数。

    1. 如果 count 1 = 0 \textit{count}_1 = 0 count1=0,则将 majority 1 \textit{majority}_1 majority1 更新为 num \textit{num} num,并将 count 1 \textit{count}_1 count1 1 1 1

    2. 否则,如果 count 2 = 0 \textit{count}_2 = 0 count2=0,则将 majority 2 \textit{majority}_2 majority2 更新为 num \textit{num} num,并将 count 2 \textit{count}_2 count2 1 1 1

  3. 如果 num \textit{num} num 和两个候选元素都不相等且两个候选元素的出现次数都大于 0 0 0,则 num \textit{num} num 和两个候选元素抵消,将 count 1 \textit{count}_1 count1 count 2 \textit{count}_2 count2 都减 1 1 1

遍历结束之后,得到两个候选元素。再次遍历数组,统计两个候选元素在数组中的出现次数,当出现次数大于 ⌊ n 3 ⌋ \Big\lfloor \dfrac{n}{3} \Big\rfloor 3n 时将候选元素添加到结果中。

代码

class Solution {
    public List<Integer> majorityElement(int[] nums) {
        int majority1 = 0, majority2 = 0;
        int count1 = 0, count2 = 0;
        for (int num : nums) {
            if (num == majority1) {
                count1++;
            } else if (num == majority2) {
                count2++;
            } else if (count1 == 0) {
                majority1 = num;
                count1++;
            } else if (count2 == 0) {
                majority2 = num;
                count2++;
            } else {
                count1--;
                count2--;
            }
        }
        count1 = 0;
        count2 = 0;
        for (int num : nums) {
            if (num == majority1) {
                count1++;
            } else if (num == majority2) {
                count2++;
            }
        }
        List<Integer> majorities = new ArrayList<Integer>();
        int n = nums.length;
        if (count1 > n / 3) {
            majorities.add(majority1);
        }
        if (count2 > n / 3) {
            majorities.add(majority2);
        }
        return majorities;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。需要遍历数组 nums \textit{nums} nums 两次。

  • 空间复杂度: O ( 1 ) O(1) O(1)

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

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

相关文章

error LNK2019: 无法解析的外部符号 _SDL_main,该符号在函数 _main_getcmdline 中被引用

VC MFC情况下出现此问题&#xff0c; 网上搜索了很多文章无法解决。 error LNK2019: 无法解析的外部符号 _SDL_main&#xff0c;该符号在函数 _main_utf8 中被引用_sdl2main.lib出现无法解析的外部符号-CSDN博客 字符集必须设置为&#xff1a;

【Android面试八股文】性能优化相关面试题: 什么是内存抖动?什么是内存泄漏?

文章目录 一、什么是内存抖动?内存抖动的问题卡顿OOM(Out Of Memory)二、什么是内存泄漏(Memory Leak)?引用计数法可达性分析法一、什么是内存抖动? 在Java中,每创建一个对象,就会申请一块内存,存储对象信息; 每分配一块内存,程序的可用内存也就少一块; 当程序…

SwiftUI八与UIKIT交互

代码下载 SwiftUI可以在苹果全平台上无缝兼容现有的UI框架。例如&#xff0c;可以在SwiftUI视图中嵌入UIKit视图或UIKit视图控制器&#xff0c;反过来在UIKit视图或UIKit视图控制器中也可以嵌入SwiftUI视图。 本文展示如何把landmark应用的主页混合使用UIPageViewController和…

VaRest插件常用节点以及Http请求数据

1.解析json &#xff08;1&#xff09;Construct Json Object&#xff1a;构建json对象 &#xff08;2&#xff09;Decode Json&#xff1a;解析json 将string转换为json &#xff08;3&#xff09;Encode json&#xff1a;将json转换为string &#xff08;4&#xff09;Get S…

非标设备行业的数智化项目管理

近年来&#xff0c;中国制造快速发展&#xff0c;企业迫切需要加快转型升级。与传统制造业相比&#xff0c;高端制造业具有明显的优势&#xff1a;高技术、高附加值、低污染、低排放、竞争优势强。一方面&#xff0c;企业对于生产效率和自动化水平的要求不断提高&#xff0c;期…

[vue2/vue3] 详细剖析watch、computed、watchEffect的区别,原理解读

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;我是前端菜鸟的自我修养&#xff01;今天给大家分享【深入剖析watch、computed、watchEffect的区别】&#xff0c;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;原创不易&#xff0c;如果能帮助到带大家…

安装docker compose与elasticsearch,kibana

1.docker compose安装 1.1是否已安装docker docker -v 1.2安装docker compose curl -SL https://github.com/docker/compose/releases/download/v2.18.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-composeps:如果网络太慢可直接在博客中下载附属文件 下载后修…

缺失d3dx9_43.dll是怎么回事?教你几种靠谱的解决方法

在日常生活和工作中&#xff0c;电脑已经成为我们不可或缺的工具。然而&#xff0c;在使用电脑的过程中&#xff0c;我们常常会遇到一些问题&#xff0c;其中之一就是软件运行时提示d3dx9_43.dll丢失。这个问题会导致软件游戏无法启动运行&#xff0c;但只要我们了解其原因和解…

光扩散微球市场增长空间大 我国已实现其产业化

光扩散微球市场增长空间大 我国已实现其产业化 光扩散微球是一种高性能微球材料&#xff0c;具有优异的光学和力学性能&#xff0c;且不含杂质&#xff0c;将其涂抹在光扩散膜&#xff08;板&#xff09;上&#xff0c;可以将点光源变成面光源&#xff0c;使显示面板的布光更加…

论文阅读YOLO-World: Real-Time Open-Vocabulary Object Detection

核心&#xff1a; 开放词汇的实时的yolo检测器。重参数化的视觉语言聚合路径模块Re-parameterizable VisionLanguage Path Aggregation Network (RepVL-PAN)实时核心&#xff1a;轻量化的检测器离线词汇推理过程重参数化 方法 预训练方案&#xff1a;将实例注释重新定义为区域…

喜讯!安全狗荣获“2023年网络安全技术支撑优秀单位”称号

6月6日&#xff0c;由中共厦门市委网络安全和信息化委员会办公室&#xff08;以下简称“厦门市委网信办”&#xff09;主办的2023年网络安全技术支撑优秀单位颁奖仪式在厦门成功举行。 作为国内云原生安全领导厂商&#xff0c;安全狗受邀出席此次活动。 会上&#xff0c;安全狗…

【ai】ubuntu18.04 找不到 nvcc --version问题

nvcc --version显示command not found问题 这个是cuda 库: windows安装了12.5 : 参考大神:解决nvcc --version显示command not found问题 原文链接:https://blog.csdn.net/Flying_sfeng/article/details/103343813 /usr/local/cuda/lib64 与 /usr/local/cuda-11.3/lib64 完…

OZON家具用品有哪些是热销的

在俄罗斯电商市场中&#xff0c;OZON平台凭借其强大的影响力和广泛的用户基础&#xff0c;成为家具用品销售的重要阵地。那么&#xff0c;在这个平台上&#xff0c;哪些家具用品最受欢迎&#xff0c;销量持续走高呢&#xff1f;本文将为您揭秘OZON家具用品的热销秘诀&#xff0…

Golang开发:构建支持并发的网络爬虫

Golang开发&#xff1a;构建支持并发的网络爬虫 随着互联网的快速发展&#xff0c;获取网络数据成为了许多应用场景中的关键需求。网络爬虫作为一种自动化获取网络数据的工具&#xff0c;也因此迅速崛起。而为了应对日益庞大的网络数据&#xff0c;开发支持并发的爬虫成为了必…

INS-GPS组合导航——卡尔曼滤波

系列文章目录 《SAR笔记-卫星轨道建模》 《SAR笔记-卫星轨迹&#xff08;三维建模&#xff09;》 《常用坐标系》 文章目录 前言 一、经典卡尔曼滤波 二、扩展卡尔曼滤波 三、无迹卡尔曼滤波 总结 前言 SAR成像仪器搭载于运动平台&#xff0c;平台的自定位误差将影响SAR…

20240701每日后端------------java启动JVM参数配置说明Parameters -D, -X, -XX

主题 JVM有很多参数&#xff0c;当我们通过命令行启动Java程序时&#xff08;例如&#xff0c; java -jar app.jar&#xff09; 我们经常指定各种参数选项。很多人对为什么有时我们使用 -D &#xff0c;有时我们使用 -X &#xff0c;偶尔我们使用 -XX 感到困惑。 名词解释 …

08:结构体

结构体 1、为什么需要结构体2、如何定义结构体3、怎么使用结构体变量3.1、赋值和初始化3.2、结构体变量的输出 1、为什么需要结构体 为了表示一些复杂的事物&#xff0c;而普通的基本类型无法满足实际要求。什么叫结构体 把一些基本类型数据组合在一起形成的一个新的数据类型&…

深入剖析Tomcat(十四) Server、Service 组件:如何启停Tomcat服务?

通过前面文章的学习&#xff0c;我们已经了解了连接器&#xff0c;四大容器是如何配合工作的&#xff0c;在源码中提供的示例也都是“一个连接器”“一个顶层容器”的结构。并且启动方式是分别启动连接器和容器&#xff0c;类似下面代码 connector.setContainer(engine); try …

DP V2.1a标准学习

一、说明 DP是DisplayPort的简写,是视频电子标准协会(VESA)标准化的数字式视频接口标准,可用于板内芯片之间的连接,也可用于输出接口连接外部设备。DisplayPort是一种基于数据包的可扩展协议,用于传输视频和音频数据。DisplayPort 具有高度可扩展性,并具有保持向后兼容…

【一步一步了解Java系列】:对这个系列的总结以及对缺漏内部类知识的补充

看到这句话的时候证明&#xff1a;此刻你我都在努力 加油陌生人 br />个人主页&#xff1a;Gu Gu Study专栏&#xff1a;一步一步了解Java 喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努力留下足迹 喜欢的话可以点个赞谢谢了。 作者&#xf…