面试经典150题——多数元素

news2024/11/23 2:01:06

目录

题目链接:169. 多数元素 - 力扣(LeetCode)

题目描述

示例

提示:

解法一:哈希表

Java写法:

C++写法:

解法二:它就在那里

Java写法:

C++写法:

解法三:摩尔投票算法

Java写法:

C++写法:

总结


题目链接:169. 多数元素 - 力扣(LeetCode)

注:下述题目描述和示例均来自力扣

题目描述

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例

示例 1:

输入:nums = [3,2,3]
输出:3

示例 2:

输入:nums = [2,2,1,1,1,2,2]
输出:2

提示:

  • n == nums.length
  • 1 <= n <= 5 * 10^4
  • -10^9 <= nums[i] <= 10^9

解法一:哈希表

我们就不要尝试暴力的方式了,因为数据已经到了10^9这个量级了,这个必然是会超时的。

  1. 初始化数据结构:首先,创建一个HashMap<Integer, Integer>来存储数组中每个元素及其对应的出现次数。这个哈希表将作为计数器,用于记录每个元素在数组中出现了多少次。

  2. 遍历数组:然后,遍历输入的整数数组nums。对于数组中的每个元素num,执行以下操作:

    • 使用countMap.getOrDefault(num, 0)方法检查num是否已经在哈希表中作为键存在。如果存在,则返回其对应的值(即出现次数);如果不存在,则返回默认值0。
    • 将该元素的出现次数加1,并更新哈希表中该元素的计数。这是通过countMap.put(num, countMap.getOrDefault(num, 0) + 1)实现的。
  3. 检查多数元素:在遍历过程中,每次更新完哈希表后,都检查当前元素的计数是否已经超过数组长度的一半(即half变量)。这是通过if (countMap.get(num) > half)判断条件实现的。如果找到了这样的元素,说明它已经满足了多数元素的条件(即出现次数大于数组长度的一半),因此直接返回该元素。

  4. 处理理论上的不可能情况:虽然题目已经保证了多数元素的存在,但为了代码的健壮性,还是保留了一个返回值-1。这个返回值在理论上不会被执行到,因为它表示没有找到多数元素。然而,在实际应用中,如果输入不满足题目的条件(即不存在多数元素),这个返回值就变得有用了。不过,在本题的情况下,由于题目已经明确给出了多数元素的存在性,所以这个返回值更多是作为一个安全网或代码健壮性的体现。

  5. 返回结果:如果在遍历过程中找到了多数元素,就直接返回它。如果遍历结束还没有返回(这在题目给定条件下是不可能发生的),则理论上会执行到返回-1的代码行,但实际上不会。

Java写法:

class Solution {
    /**  
     * 找到数组中的多数元素,即出现次数大于数组长度一半的元素。  
     *   
     * @param nums 输入的整数数组  
     * @return 数组中的多数元素  
     */  
    public int majorityElement(int[] nums) {  
        // 创建一个HashMap来存储每个元素及其出现次数  
        HashMap<Integer, Integer> countMap = new HashMap<>();  
        // 获取数组长度  
        int n = nums.length;  
        // 计算多数元素至少需要出现的次数  
        int half = n / 2;  
  
        // 遍历数组中的每个元素  
        for (int num : nums) {  
            // 如果HashMap中已经存在该元素,则更新其计数  
            // 如果不存在,则使用getOrDefault方法返回0并加1  
            countMap.put(num, countMap.getOrDefault(num, 0) + 1);  
            // 检查当前元素的计数是否已经超过半数  
            // 如果是,则直接返回该元素,因为它就是多数元素  
            if (countMap.get(num) > half) {  
                return num;  
            }  
        }  
  
        // 理论上,由于题目保证了多数元素的存在,这里不会被执行到  
        // 但为了代码的健壮性,还是保留一个返回值  
        // 在实际使用中,可以根据需要抛出异常或进行其他处理  
        return -1; // 表示没有找到多数元素(但实际上根据题目,这种情况不会发生)  
    }  
}

C++写法:

class Solution {
public:
    int majorityElement(vector<int>& nums) {
std::unordered_map<int, int> countMap;  
        int n = nums.size();  
        int half = n / 2;  
  
        for (int num : nums) {  
            countMap[num]++;  
            if (countMap[num] > half) {  
                return num;  
            }  
        }  
  
        // 理论上不会执行到这里,因为题目保证了多数元素的存在  
        // 但为了代码的健壮性,可以抛出一个异常或返回一个特殊值  
        return 1;
    }  
};



解法二:它就在那里

  1. 排序:首先,使用Arrays.sort(nums)对数组nums进行排序。这一步是算法中最耗时的部分,因为排序算法(如快速排序、归并排序等)的时间复杂度通常是O(n log n),其中n是数组的长度。

  2. 找到多数元素:由于题目保证了多数元素的存在,并且其出现次数大于数组长度的一半,因此在排序后的数组中,多数元素一定会出现在数组的中间位置(即索引为nums.length / 2的位置)。这是因为,在排序后的数组中,所有小于多数元素的元素都会排在它前面,所有大于它的元素都会排在它后面,而由于它的出现次数超过了一半,所以它的位置必然在中间。

  3. 返回结果:直接返回nums[nums.length / 2],即排序后数组的中间元素,作为多数元素。

Java写法:

class Solution {
    public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length / 2];
    }
}

 

C++写法:

这个就不用给C++写法了吧,这如此简明扼要了哈哈哈哈。




解法三:摩尔投票算法

        摩尔投票算法(Boyer-Moore Voting Algorithm),用于在一个数组中找到出现次数超过数组长度一半的元素(多数元素)。这种算法的核心思想是通过遍历数组来维护一个候选的多数元素及其计数器,从而有效地找到真正的多数元素。

以下是该代码实现思路的详细讲解:

  1. 初始化候选元素和计数器
    • 选择数组中的第一个元素作为初始的候选元素(candidate)。
    • 将计数器(count)初始化为1,因为我们已经有一个候选元素了。
  2. 遍历数组
    • 从数组的第二个元素开始遍历(因为第一个元素已经被选为初始候选元素了)。
    • 对于每个遍历到的元素,执行以下操作:
      • 如果计数器为0,说明当前的候选元素已经不再是多数元素的候选者(因为其他元素已经“抵消”了它的所有出现次数)。此时,将当前遍历到的元素设为新的候选元素,并将计数器重置为1。
      • 如果当前遍历到的元素与候选元素相同,说明找到了一个支持候选元素的元素,将计数器加1。
      • 如果当前遍历到的元素与候选元素不同,说明找到了一个不支持候选元素的元素,将计数器减1。这可以理解为“抵消”了候选元素的一个出现次数。
  3. 返回候选元素
    • 遍历结束后,由于题目保证了多数元素的存在,并且其出现次数超过数组长度的一半,因此候选元素最终一定是多数元素。
    • 直接返回候选元素作为结果。

        这个算法之所以有效,是因为它利用了多数元素的特性:多数元素的数量超过了数组长度的一半。这意味着在遍历过程中,无论我们如何选择候选元素和进行抵消操作,多数元素始终能够“存活”到最后,成为最终的候选元素。

        该算法的时间复杂度为O(n),因为我们只遍历了一次数组。空间复杂度为O(1),因为我们只使用了常量级别的额外空间来存储候选元素和计数器。这使得摩尔投票算法成为解决这类问题的非常高效和优雅的方法。

Java写法:

class Solution {
    public int majorityElement(int[] nums) {
        // 初始化候选元素为数组的第一个元素
        int candidate = nums[0];   
        // 初始化计数器为1
        int count = 1;   
  
        for (int i = 1; i < nums.length; i++) {  
            if (count == 0) {  
                // 计数器为0时,更换候选元素  
                candidate = nums[i];  
                count = 1;  
            } else if (candidate == nums[i]) {  
                // 候选元素与当前元素相同,计数器加1  
                count++;  
            } else {  
                // 候选元素与当前元素不同,计数器减1  
                count--;  
            }  
        }  
  
        // 遍历结束后,candidate就是多数元素  
        return candidate;  
    }  
}

C++写法:

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        std::unordered_map<int, int> countMap;  
        // 初始化候选元素为数组的第一个元素  
        int candidate = nums[0]; 
        // 初始化计数器为1
        int count = 1;   
  
        for (int i = 1; i < nums.size(); ++i) {  
            if (count == 0) {  
                // 计数器为0时,更换候选元素  
                candidate = nums[i];  
                count = 1;  
            } else if (candidate == nums[i]) {  
                // 候选元素与当前元素相同,计数器加1  
                count++;  
            } else {  
                // 候选元素与当前元素不同,计数器减1  
                count--;  
            }  
        }  
  
        // 遍历结束后,candidate就是多数元素  
        return candidate;  
    }  
};

 


 

总结

三种解法,大家好好看看吧~~~~

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

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

相关文章

求n至少为多大时,n个1组成的整数能被2013整除

题目&#xff1a;编写程序&#xff0c;求n至少为多大时&#xff0c;n个1组成的整数能被2013整除 #include<iostream> using namespace std; int main(){int n1;int m1;while(m%2013!0){m(m%2013)*101;n;}cout<<n<<endl;return 0; } 思路&#xff1a;直接用n…

2024年上海小学生古诗文大会倒计时一个月:做几道2024官方模拟题

2024年上海市小学生古诗文大会自由报名活动的初赛日期于10月19日开始&#xff0c;距离今天只有33天了。 那么如何准备2024年的小学生古诗文大会的自由报名初选呢&#xff1f;吃透&#xff08;记熟&#xff09;2024年小学生古诗文阅读专辑上的题目、知识点和往年真题及知识点。…

Linux memcg lru lock提升锁性能

内核关于per memcg lru lock的重要提交&#xff1a; f9b1038ebccad354256cf84749cbc321b5347497 6168d0da2b479ce25a4647de194045de1bdd1f1d 计算虚拟地址转换基本机制 为了处理多应用程序的地址冲突&#xff0c; linux 系统在应用中使用了虚拟地址&#xff0c;得益于硬件的…

【C++题目】1.日期差值

日期差值 题目&#xff1a; 链接&#x1f517;&#xff1a;日期差值 代码&#xff1a; #include <iostream> using namespace std; /* *思路&#xff1a; * 1. 分别求出每一个日期与0000年0月1日距离的天数 * 2. 两个距离天数相减即可得到两个日期相差的天数 *///平年…

AIGC图片相关知识和实战经验(Flux.1,ComfyUI等等)

最近看了网上的一些新闻&#xff0c;flux.1火出圈了&#xff0c;因此自己也尝试跑了一下&#xff0c;作图的质量还是蛮高的&#xff0c;在这里做个知识总结回顾。 flux.1是什么&#xff1f; 根据介绍&#xff0c;flux.1是由stable diffusion 一作&#xff0c;Stability AI的核…

基于ssm的个性化影片推荐系统设计与实现

需要项目源码请联系我&#xff0c;目前有各类成品 毕设 javaweb ssh ssm springboot等等项目框架&#xff0c;源码丰富。 专业团队&#xff0c;咨询就送开题报告&#xff0c;活动限时免费&#xff0c;有需要的朋友可以来咨询。 一、摘要 随着科学技术的飞速发展&#xff0c;社…

matlab DFT的点数与周期

只需要0——N-1个点就可以算得另一个域全部的信号 周期 时域信号的全部长度时一个周期&#xff0c;所以时域的周期化没有混叠 频域的周期与采样率有关&#xff0c;会混叠。 取一个周期进行傅里叶变换都是对于周期化后的信号取得&#xff0c;由于时域周期化不混叠&#xff0c;所…

全方位解读信息架构:从挑战到解决方案,推动企业数字化转型的全面指南

在数字经济迅猛发展的今天&#xff0c;信息架构 已经成为企业实现数字化转型、提高运营效率和优化 IT 投资的关键手段。无论是初创企业还是成熟企业&#xff0c;构建和实施有效的信息架构不仅能支持业务增长&#xff0c;还能确保数据安全和合规性。《信息架构&#xff1a;商业智…

node.js 中的进程和线程工作原理

本文所有的代码均基于 node.js 14 LTS 版本分析 概念 进程是对正在运行中的程序的一个抽象&#xff0c;是系统进行资源分配和调度的基本单位&#xff0c;操作系统的其他所有内容都是围绕着进程展开的 线程是操作系统能够进行运算调度的最小单位&#xff0c;其是进程中的一个执…

Zookeeper学习

文章目录 学习第 1 章 Zookeeper 入门1.1 概述Zookeeper工作机制 1.2 特点1.3 数据结构1.4 应用场景统一命名服务统一配置管理统一集群管理服务器动态上下线软负载均衡 1.5 下载zookeeper 第 2 章 Zookeeper 本地安装2.1 本地模式安装安装前准备配置修改操作 Zookeeper本地安装…

【三方演化博弈】模型构建与模型求解

一、背景介绍二、收益矩阵计算2.1 博弈主体策略2.2 概率2.3 具体公式2.4 计算过程&#xff08;1&#xff09;企业&#xff08;2&#xff09;政府&#xff08;3&#xff09;环境NGO 三、期望与复制动态方程3.1 企业平均期望3.2 政府平均期望3.3 环境NGO平均期望3.4 三方演化博弈…

旋转链表问题(python3)

旋转链表 问题描述解题思路代码实现 问题描述 给你一个链表的头节点 head &#xff0c;旋转链表&#xff0c;将链表每个节点向右移动 k 个位置。 输入&#xff1a;head [1,2,3,4,5], k 2 输出&#xff1a;[4,5,1,2,3] 链表中节点的数目在范围 [0, 500] 内-100 < Node.va…

robomimic基础教程(一)——基本概念

robosuite和robomimic都是由ARISE Initiative开发的开源工具&#xff0c;旨在推进机器人学习和机器人操作领域的研究。 一、基本概念 robomimic是一个用于机器人示范学习的框架。它提供了在机器人操作领域收集的大量示范数据集&#xff0c;以及用于从这些数据集中学习的离线学…

828华为云征文|华为云Flexus云服务器X实例之openEuler系统下打造EnBizCard个人电子名片

828华为云征文&#xff5c;华为云Flexus云服务器X实例之openEuler系统下打造EnBizCard个人电子名片 一、Flexus云服务器X实例介绍1.1 Flexus云服务器X实例简介1.2 Flexus云服务器X实例特点1.3 Flexus云服务器X实例使用场景 一、EnBizCard介绍2.1 EnBizCard简介2.2 EnBizCard特点…

CSS调整背景

一、设置背景颜色 通过 background-color 属性指定&#xff0c;值可以是十六进制 #ffffff&#xff0c;也可以是rgb(0, 255, 255)&#xff0c;或是颜色名称 "red" div {background-color: red; /* 通过颜色名称设置 */background-color: #ff0000; /* 通过十六进制设…

数据结构和算法之线性结构

原文出处:数据结构和算法之线性结构 关注码农爱刷题&#xff0c;看更多技术文章&#xff01;&#xff01;&#xff01; 线性结构是一种逻辑结构&#xff0c;是我们编程开发工作应用最广泛的数据结构之一。线性结构是包含n个相同性质数据元素的有限序列。它的基本特征是&…

求和(2)

题目描述 输入两个正整数 l,r&#xff0c;编程计算 l(l1)(l2)...(r−1)r 的结果并输出。 输入格式 一行两个整数 l 和 r 输出格式 一个整数&#xff0c;根据题意计算后的结果 样例数据 样例输入#1 1 5样例输出#1 15样例输入#2 8 10样例输出#2 27数据范围 对于100%的…

刷题DAY38

原样输出 题目&#xff1a;给定一个数n&#xff0c;请原样输出 输入&#xff1a;输入只有一个数&#xff0c;可能为小数&#xff0c;也可能为整数&#xff0c;-1000000<n<1000000 输出&#xff1a;原样输出 输入&#xff1a;1.123 输出&#xff1a;1.123 import ja…

鸿蒙媒体开发系列01——资源分类访问

如果你也对鸿蒙开发感兴趣&#xff0c;加入“Harmony自习室”吧&#xff01;扫描下方名片&#xff0c;关注公众号&#xff0c;公众号更新更快&#xff0c;同时也有更多学习资料和技术讨论群。 1、概述 应用开发过程中&#xff0c;经常需要用到颜色、字体、间距、图片等资源&am…

代码随想录刷题day34丨 62.不同路径 ,63. 不同路径 II

代码随想录刷题day34丨 62.不同路径 &#xff0c;63. 不同路径 II 1.题目 1.1不同路径 题目链接&#xff1a;62. 不同路径 - 力扣&#xff08;LeetCode&#xff09; 视频讲解&#xff1a;动态规划中如何初始化很重要&#xff01;| LeetCode&#xff1a;62.不同路径_哔哩哔哩…