当前位置: 首页 > news >正文

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

目录

题目链接: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];   // 初始化计数器为1int 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]; // 初始化计数器为1int 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;  }  
};

 


 

总结

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

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 基于深度学习的因果推理与决策
  • AI+RPA 实战揭秘:DrissionPage 助力 CSDN 热榜数据抓取与 AI 结合
  • 跨界融合,GIS如何赋能游戏商业——以《黑神话:悟空》为例
  • 2024最新版,人大赵鑫老师《大语言模型》新书pdf分享
  • FPGA与Matlab图像处理之伽马校正
  • RusTitW:大规模语言视觉文本识别数据集(猫脸码客 第190期)
  • CAD图纸加密软件哪个好?10款2024主流CAD图纸加密软件分享!
  • 监控易监测对象及指标之:全面监控FTP服务器
  • ubuntu服务器版NVIDIA驱动失效解决方案
  • 宝塔Linux部署 Vue + Spring Boot + MySQL + Redis
  • C++中一般指针,指针数组,数组指针
  • Java入门,初识Java
  • web基础—dvwa靶场(五)File Upload
  • 【CMake】使用CMake在VIsual Studio内构建多文件夹工程
  • JavaScript 事件处理
  • [iOS]Core Data浅析一 -- 启用Core Data
  • 11111111
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • Java 最常见的 200+ 面试题:面试必备
  • java取消线程实例
  • JS基础之数据类型、对象、原型、原型链、继承
  • JWT究竟是什么呢?
  • Nacos系列:Nacos的Java SDK使用
  • React as a UI Runtime(五、列表)
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 高程读书笔记 第六章 面向对象程序设计
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 基于遗传算法的优化问题求解
  • 你真的知道 == 和 equals 的区别吗?
  • 前端
  • 前端面试题总结
  • 区块链共识机制优缺点对比都是什么
  • 东超科技获得千万级Pre-A轮融资,投资方为中科创星 ...
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • ​HTTP与HTTPS:网络通信的安全卫士
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • !$boo在php中什么意思,php前戏
  • # Panda3d 碰撞检测系统介绍
  • #etcd#安装时出错
  • #laravel部署安装报错loadFactoriesFrom是undefined method #
  • (70min)字节暑假实习二面(已挂)
  • (day6) 319. 灯泡开关
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (论文阅读笔记)Network planning with deep reinforcement learning
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (学习日记)2024.01.09
  • (转)fock函数详解
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • **PHP分步表单提交思路(分页表单提交)