题目

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/majority-element/

注意,该题在LC中被标注为easy,所以我们更多应该关注的是文章中不断优化的思路和方法。很多时候面试考察的,就是与面试官一起做题并把时间复杂度和空间复杂度压榨到极致的过程中你所表现出来的能力。

1.描述

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

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

2.示例

  • 示例 1:
	输入:[3,2,3]
输出:3
  • 示例 2:
	输入:[2,2,1,1,1,2,2]
输出:2

解法一 排序

解题思路

很快啊,啪的一下我们想到,由于多数元素是指在数组中出现次数 大于 ⌊n/2⌋ 的元素,那么将数组排序后,即便该元素是最小元素或是最大元素,其在数组中的覆盖范围也超过了数组中点(从左到右超过或是从右到左超过)。于是得到算法:

算法

1.将数组排序;

2.返回数组中点元素nums[nums.size()/2].

代码

1 class Solution {
2 public:
3 int majorityElement(vector<int>& nums) {
4 sort(nums.begin(), nums.end());//对数组进行排序
5 return nums[nums.size()/2];//返回数组中点元素
6 }
7 };

复杂度分析

时间复杂度: O(mlogm)。m为数组元素数,主要是排序的时间消耗。

空间复杂度: O(logm)。主要是系统sort函数需要的栈空间消耗。

解法二 哈希

解题思路

这时候,面试官说,你这解法一的时间复杂度很大啊,你能优化一下吗。稍加思索,我们想到,如果考虑使用哈希表空间换时间,则可以降低时间复杂度。我们可以使用哈希表存储数组中元素出现的次数,当某个元素的出现次数超过一半时,返回该元素。于是得到算法:

算法

1.初始化存储数组元素及其出现次数的哈希表map1,键为元素值,值为该元素在数组中的出现次数;

2.遍历数组元素,将被遍历数组元素的哈希值加一;

3.若该元素在数组中的出现次数超过数组元素数的一半,返回该元素。

代码

 1 class Solution {
2 public:
3 int majorityElement(vector<int>& nums) {
4 unordered_map<int, int> map1;//存储数组元素值及出现次数的哈希表
5 for(int i = 0; i < nums.size(); i++)//遍历数组元素
6 {
7 map1[nums[i]]++;//该元素出现次数加一
8 if(map1[nums[i]] > nums.size()/2)//若该元素出现此处超过一半
9 {
10 return nums[i];//返回该元素
11 }
12 }
13 return 0;//为了能通过编译
14 }
15 };

复杂度分析

时间复杂度: O(m)。遍历数组元素的时间开销。

空间复杂度: O(m)。哈希表的空间消耗。

解法三 随机算法

解题思路

这时候面试官又说了,你这解法二空间复杂度连解法一都不如,再想想有没有更好的解法。

手扶下巴,眉头一皱,我们又想到,由于多数元素是指在数组中出现次数大于⌊n/2⌋ 的元素,因此如果我们随机选取数组中的一个元素,那么将有超过1/2的概率选到该多数元素。于是可以使用这种算法:

算法

1.在数组中随机挑选一个元素;

2.遍历数组统计该元素出现次数,若超过数组元素数的一半,返回该元素,否则重新随机挑选一个元素。

代码

 1 class Solution {
2 public:
3 int majorityElement(vector<int>& nums) {
4 int m = nums.size();//计算数组元素数
5 srand(time(NULL));//设置随机数种子
6 int n;//存储随机数
7 int count = 0;//初始化以随机数为下标的元素的出现次数为0
8 while(count<=m/2){//当以随机数为下标的元素出现次数未超过数组元素数的一般
9 n = rand()%m;//获取一个随机数
10 count = 0;//初始化以随机数为下标的元素出现次数为0
11 for(int num : nums) if(num == nums[n]) ++count;//统计以随机数为下标的元素出现次数
12 }
13 return nums[n];//若以该随机数为下标的元素出现次数超过数组元素数的一半,返回以该随机数为下标的元素
14 }
15 };

复杂度分析

时间复杂度: O(m)。理论上最坏情况下复杂度为O(∞),但实际上由于多数元素出现次数超过数组元素数的一半,平均情况下只需要两次就能选出多数元素,主要的时间开销是统计出现次数,其时间复杂度为O(m)。

空间复杂度: O(1)。只需常数个额外空间。

解法四 摩尔投票法

解题思路

面试官觉得你这解法很有意思,然后又问,那要我就是非酋呢,那岂不是无限循环了,有没有更好的办法。

这下可让人犯了难,有什么更好的办法既能时间最优又能空间最优呢?

考虑这样一个场景,一群人打擂台,人群中分为不同的帮派,挨个上台比武。留在台上的帮派为擂主帮派,如果上台的人不是自己帮派的人,则将其干掉,代价是损失一个帮派成员;如果上台的人是自己帮派的人,则将其留下。则当所有人都参与完比武后,留在台上的必然可以是人数超过比武人数一半的帮派。而在本题中,多数元素出现次数超过数组元素数的一半,也即,其他所有元素加起来都没多数元素多。如果我们记多数元素的值为1,其他元素的值为0,将数组中所有元素值相加,结果必然大于0。于是我们可以设计这样一种算法:

算法

1.初始化候选答案ans为nums[0],初始化数值计算结果count为0;

2.遍历数组若该元素与备选答案相等,count加一,否则减一;

3.若count减为零,更换备选答案ans为当前元素,重置count为1,继续遍历后续元素。

遍历完成后返回最终的ans即为多数元素。

代码

 1 class Solution {
2 public:
3 int majorityElement(vector<int>& nums) {
4 int ans = nums[0];//初始化候选答案为nums[0]
5 int count = 0;//初始化数值计算结果为0
6 for(auto num : nums){//遍历数组
7 if(num==ans) ++count;//若该元素与备选答案相同,则count加一
8 else{//否则减一
9 --count;
10 if(count==0){//若count减为0
11 ans = num;//更换备选答案为当前元素
12 ++count;//重置count为1
13 }
14 }
15 }
16 return ans;//返回答案
17 }
18 };

复杂度分析

时间复杂度: O(m)。只需要对数组进行一次遍历即可

空间复杂度: O(1)。只需常数个额外空间。

Tips:

由于题目明确说明给定的数组中总是存在多数元素,因此本题不用考虑数组不存在多数元素的情况。若未做说明,需要像解法三那样,在选出ans以后再进行一次统计,验证该元素是否是多数元素,若果是,返回之;如果不是,返回不存在多数元素。时间复杂度和空间空间复杂度不变。

更多知识内容分享:

力扣个人主页https://leetcode-cn.com/profile/articles/

CSDN个人主页https://blog.csdn.net/qq_39255924

牛客个人主页https://blog.nowcoder.net/newcoderthewarrior

可可爱爱的蕾姆镇

【Warrior刷题笔记】力扣169. 多数元素 【排序 || 哈希 || 随机算法 || 摩尔投票法】详细注释 不断优化 极致压榨的更多相关文章

  1. 【Warrior刷题笔记】剑指offer 6 24 35. 三道题,让你学会链表递归迭代辅助栈

    题目一 从尾到头打印链表 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-l ...

  2. 【Warrior刷题笔记】剑指offer 32. 三道题,让你学会二叉树的深度广度优先遍历与递归迭代技术

    题目一 剑指 Offer 32 - I. 从上到下打印二叉树 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/cong-shang-dao-xi ...

  3. 【Warrior刷题笔记】143.重排链表 【线性化 || 双指针+翻转链表+链表合并】详细注释

    题目一 力扣143.重排链表 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/reorder-list/ 1.描述 给定一个单链表L的头节点he ...

  4. 《Data Structures and Algorithm Analysis in C》学习与刷题笔记

    <Data Structures and Algorithm Analysis in C>学习与刷题笔记 为什么要学习DSAAC? 某个月黑风高的夜晚,下班的我走在黯淡无光.冷清无人的冲之 ...

  5. Python 刷题笔记

    Python 刷题笔记 本文记录了我在使用python刷题的时候遇到的知识点. 目录 Python 刷题笔记 选择.填空题 基本输入输出 sys.stdin 与input 运行脚本时传入参数 Pyth ...

  6. PTA刷题笔记

    PTA刷题记录 仓库地址: https://github.com/Haorical/Code/tree/master/PTA/GPLT 两周之内刷完GPLT L2和L3的题,持续更新,包括AK代码,坑 ...

  7. leecode刷题(27)-- 合并k个排序链表

    leecode刷题(27)-- 合并k个排序链表 合并k个排序链表 合并 k 个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度. 示例: 输入: [ 1->4->5, 1-> ...

  8. 《Algorithms算法》笔记:元素排序(3)——洗牌算法

    <Algorithms算法>笔记:元素排序(3)——洗牌算法 Algorithms算法笔记元素排序3洗牌算法 洗牌算法 排序洗牌 Knuth洗牌 Knuth洗牌代码 洗牌算法 洗牌的思想很 ...

  9. 《剑指offer》刷题笔记

    简介 此笔记为我在 leetcode 上的<剑指offer>专题刷题时的笔记整理. 在刷题时我尝试了 leetcode 上热门题解中的多种方法,这些不同方法的实现都列在了笔记中. leet ...

随机推荐

  1. oc中调用c函数 实现将字符串转换成unsigned char

    帮助码友解决问题,从而复习了一下oc中调用c函数的方式 1,新建c 头文件  test.h 定义 c 函数 #ifndef test_h #define test_h void verificatio ...

  2. OSGI 理论知识

    下面列出了主要的控制台命令: 表 1. Equinox OSGi 主要的控制台命令表 类别 命令 含义 控制框架 launch 启动框架 shutdown 停止框架 close 关闭.退出框架 exi ...

  3. keepalived 高可用lvs的dr模型(vip与dip不在同一网段)

    现在rs1和rs2上面安装httpd并准备测试页 [root@rs1 ~]# yum install httpd -y [root@rs1 ~]# echo "this is r1" ...

  4. 远程连接mysql库问题

    如果你想连接你的mysql的时候发生这个错误: ERROR 1130: Host '192.168.1.3' is not allowed to connect to this MySQL serve ...

  5. html如何让input number类型的标签不产生上下加减的按钮(转)

    添加css代码: <style> input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit- ...

  6. 【C/C++】01背包问题/动态规划

    按小蓝书上写的大数据情况下没过,按解答区一个大佬的修改了过了 #include <bits/stdc++.h> using namespace std; class Solution { ...

  7. Jsp/Servlet文件的上传和下载

    文件上传的入门 文件上传的步骤:       总结实现思路: 1.创建核心上传类ServletFileUpload,这个时候需要一个工厂类 2.创建磁盘工厂类对象DiskFileItemFactory ...

  8. Flutter 中如何优雅的实现多渠道打包(埋点统计系列)

    我是 Zero,脑图先奉上 先赞后看,更新永不断 只要你关注 Flutter,这篇文章你绝对用得着,==> 强烈建议收藏 多渠道打包介绍 多渠道打包的主要作用是满足产品的运营需求,统计渠道和活动 ...

  9. 设计风格之REST

    一.简介 REST简介 REST 是英文 representational state transfer(表象性状态转变)或者表述性状态转 移;Rest 是 web 服务的一种架构风格;使用 HTTP ...

  10. 手把手教你提交Jar包到Maven公共仓库 | 萌新写开源02

    在上一篇文章中,我介绍了自己的SpringBoot Starter项目,可以让我们使用注解的方式轻松地获取操作日志,并推送到指定数据源. 之前,我的项目开源在Github上,大家想要用我的项目,还得把 ...