力扣 - 剑指 Offer 39. 数组中出现次数超过一半的数字
题目
思路1(排序)
- 因为题目说一定会存在超过数组长度一半的一个数字,所以我们将数组排序后,位于
length/2
位置的一定是众数
代码
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length/2];
}
}
复杂度分析
- 时间复杂度:\(O(NlogN)\)
- 空间复杂度:\(O(1)\)
思路2(哈希表)
- 遍历一遍数组,将数组的值作为键,出现的次数作为值,存放到哈希表中
- 遍历哈希表,找到出现次数最多的那一个键值对就是我们要的众数
代码
class Solution {
public int majorityElement(int[] nums) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int n : nums) {
map.put(n, map.getOrDefault(n, 0) + 1);
}
int max = 0;
int res = 0;
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (max < entry.getValue()) {
max = entry.getValue();
res = entry.getKey();
}
}
return res;
}
}
复杂度分析
- 时间复杂度:\(O(N)\)
- 空间复杂度:\(O(N)\)
思路3(分治)
- 将数组从中间开始不断分成两份,直到只剩下一个元素时候开始返回
- 如果left和right出现的频率一样,直接返回
- 计算left和right在lo~hi范围内出现的频率,将高频率的返回
- 为什么可以用这个方法?比如有
[1, 2, 3, 2, 2, 2, 5, 4, 2]
,共有9个元素,共会被分成5份(每份一个或者两个元素),然后从每份中再获取一个值,共获取5个值,又因为众数的个数要大于数组的长度,所以,众数一定会至少被选中一个,只要被选中一个,那么我们的countInRange
函数会根据范围帮我们计算出最多出现的元素个数即众数
代码
class Solution {
public int majorityElement(int[] nums) {
return majorityElementRec(nums, 0, nums.length-1);
}
public int majorityElementRec(int[] nums, int lo, int hi) {
// 如果只有一个元素,那么直接返回
if (lo == hi) {
return nums[lo];
}
// 获取中间值
int mid = lo + (hi - lo) / 2;
// 递归左边和右边,直到剩下一个元素
int left = majorityElementRec(nums, lo, mid);
int right = majorityElementRec(nums, mid+1, hi);
// 相等只需要返回一个
if (left == right) {
return left;
}
// 计算left和right在lo~hi范围中的出现的次数
int leftCount = countInRange(nums, left, lo, hi);
int rightCount = countInRange(nums, right, lo, hi);
// 返回出现次数多的数
return leftCount > rightCount ? left : right;
}
// 统计目标数字在指定范围出现的次数
public int countInRange(int[] nums, int target, int lo, int hi) {
int count = 0;
for (int i = lo; i <= hi; i++) {
if (nums[i] == target) {
count++;
}
}
return count;
}
}
复杂度分析
- 时间复杂度:\(O(NlogN)\)
- 空间复杂度:\(O(logN)\),递归过程中使用了额外的栈空间
思路4(摩尔投票法)
- 众数记为+1,把其他数记为-1,将它们全部加起来,和最终会大于0
- 假设众数记为
res
,票数记为votes
,假设有这么一个数组:[1, 2, 3, 2, 2, 2, 5, 4, 2],使用摩尔投票法的过程如下:i=0
时:因为当前票数为0,所以将1赋值给res
,同时票数也加一。此时res=1 votes=1
i=1
时:2不等于1,所以票数要减1,此时res=1 votes=0
i=2
时:因为票数为0,所以众数res要指向当前的3,然后票数加一,此时res=3 votes=1
i=3
时:2不等于3,所以票数要减1,此时res=3 votes=0
i=4
时:因为票数为0,所以众数res要指向当前的2,然后票数加一,此时res=2 votes=1
i=5
时:由于2=2
,所以票数加一,此时res=2 votes=2
i=6
时:5不等于2,所以票数要减1,此时res=2 votes=1
i=7
时:4不等于2,所以票数要减1,此时res=2 votes=0
i=8
时:因为票数为0,所以众数res要指向当前的2,然后票数加一,此时res=2 votes=1
- 最后就直接输出res即为众数
代码
class Solution {
public int majorityElement(int[] nums) {
// 代表结果的众数
int res = nums[0];
// 统计票数
int votes = 0;
for (int i = 0; i < nums.length; i++) {
// 刚开始是0票,所以把数组的第一个元素作为众数
// 如果以后的循环votes票数被抵消掉了为0,那么下一个元素就作为众数
if (votes == 0) {
res = nums[i];
}
// 和当前众数相同的,那么票数就加1
if (res == nums[i]) {
votes++;
} else {
// 如果和当前票数不同,票数就被抵消掉了一个
votes--;
}
}
return res;
}
}
复杂度分析
- 时间复杂度:\(O(N)\)
- 空间复杂度:\(O(1)\)
力扣 - 剑指 Offer 39. 数组中出现次数超过一半的数字的更多相关文章
- 剑指 Offer 39. 数组中出现次数超过一半的数字
剑指 Offer 39. 数组中出现次数超过一半的数字 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 你可以假设数组是非空的,并且给定的数组总是存在多数元素. 示例 1: 输入: [ ...
- 剑指 Offer 39. 数组中出现次数超过一半的数字 + 摩尔投票法
剑指 Offer 39. 数组中出现次数超过一半的数字 Offer_39 题目描述 方法一:使用map存储数字出现的次数 public class Offer_39 { public int majo ...
- 【Java】 剑指offer(39) 数组中出现次数超过一半的数字
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如 ...
- 每日一题 - 剑指 Offer 39. 数组中出现次数超过一半的数字
题目信息 时间: 2019-06-29 题目链接:Leetcode tag: 数组 哈希表 难易程度:简单 题目描述: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 假设数组是非空的 ...
- 剑指Offer:数组中出现次数超过一半的数字【39】
剑指Offer:数组中出现次数超过一半的数字[39] 题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如,输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于这 ...
- 【剑指Offer】数组中出现次数超过一半的数字 解题报告(Python)
[剑指Offer]数组中出现次数超过一半的数字 解题报告(Python) 标签(空格分隔): 剑指Offer 题目地址:https://www.nowcoder.com/ta/coding-inter ...
- Go语言实现:【剑指offer】数组中出现次数超过一半的数字
该题目来源于牛客网<剑指offer>专题. 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组 ...
- 剑指OFFER之数组中出现次数超过一半的数字(九度OJ1370)
题目描述: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2 ...
- 剑指Offer 28. 数组中出现次数超过一半的数字 (数组)
题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. ...
随机推荐
- adb 常用命令大全(5)- 日志相关
前言 Android 系统的日志分为两部分 底层的 Linux 内核日志输出到 /proc/kmsg Android 的日志输出到 /dev/log 语法格式 adb logcat [<opti ...
- IPsec 9个包分析(主模式+快速模式)
第一阶段:ISAKMP协商阶段 1.1 第一包 包1:发起端协商SA,使用的是UDP协议,端口号是500,上层协议是ISAKMP,该协议提供的是一个框架,里面的负载Next payload类似模块,可 ...
- 使用GitHub Pages + docsify快速搭建一个站点
话不多说,先看效果: https://bytesfly.github.io/blog 为什么需要一个站点 肯定有人会问,既然有类似 博客园 这样优秀的平台来写博客,为什么还需要自己搭建站点呢? 放在G ...
- 343 day08File类、递归
day08[File类.递归] 主要内容 File类 递归 教学目标 [ ] 能够说出File对象的创建方式 [ ] 能够说出File类获取名称的方法名称 [ ] 能够说出File类获取绝对路径的方法 ...
- java.lang.NullPointerException: Attempt to invoke virtual method 'int com.example.xxx.Json.NewsBean.getError_code()' on a null object reference错误解决
AS在运行的过程中出现了错误: java.lang.NullPointerException: Attempt to invoke virtual method 'int com.example.xx ...
- Python测试框架对比----unittest, pytest, nose, robot framework对比
什么是框架? 框架(Framework)是整个或部分系统的可重用设计, 框架是用来解决代码的组织及运行控制问题的. 在我们编写自动化脚本的时候,经常需要读取配置文件,读取数据文件,发送请求,记录日志, ...
- 一文让你彻底理解SELECT语句的执行逻辑
正常情况下SELECT的书写顺序和执行顺序: 书写顺序: SELECT>FROM >WHERE>GROUP BY>HAVE>ORDER BY 执行顺序: FROM > ...
- python对象引用和垃圾回收
变量="标签" 变量a和变量b引用同一个列表: >>> a = [1, 2, 3] >>> b = a >>> a.appen ...
- AT3945-[ARC092D]Two Faced Edges【dfs】
正题 题目链接:https://www.luogu.com.cn/problem/AT3945 题目大意 \(n\)个点\(m\)条边的一张图,对于每条边求它翻转后强连通分量数量是否变化. \(1\l ...
- SpringBoot之SpringSecurity权限注解在方法上进行权限认证多种方式
前言 Spring Security支持方法级别的权限控制.在此机制上,我们可以在任意层的任意方法上加入权限注解,加入注解的方法将自动被Spring Security保护起来,仅仅允许特定的用户访问, ...