题目

剑指 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. 数组中出现次数超过一半的数字的更多相关文章

  1. 剑指 Offer 39. 数组中出现次数超过一半的数字

    剑指 Offer 39. 数组中出现次数超过一半的数字 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 你可以假设数组是非空的,并且给定的数组总是存在多数元素. 示例 1: 输入: [ ...

  2. 剑指 Offer 39. 数组中出现次数超过一半的数字 + 摩尔投票法

    剑指 Offer 39. 数组中出现次数超过一半的数字 Offer_39 题目描述 方法一:使用map存储数字出现的次数 public class Offer_39 { public int majo ...

  3. 【Java】 剑指offer(39) 数组中出现次数超过一半的数字

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如 ...

  4. 每日一题 - 剑指 Offer 39. 数组中出现次数超过一半的数字

    题目信息 时间: 2019-06-29 题目链接:Leetcode tag: 数组 哈希表 难易程度:简单 题目描述: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 假设数组是非空的 ...

  5. 剑指Offer:数组中出现次数超过一半的数字【39】

    剑指Offer:数组中出现次数超过一半的数字[39] 题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如,输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于这 ...

  6. 【剑指Offer】数组中出现次数超过一半的数字 解题报告(Python)

    [剑指Offer]数组中出现次数超过一半的数字 解题报告(Python) 标签(空格分隔): 剑指Offer 题目地址:https://www.nowcoder.com/ta/coding-inter ...

  7. Go语言实现:【剑指offer】数组中出现次数超过一半的数字

    该题目来源于牛客网<剑指offer>专题. 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组 ...

  8. 剑指OFFER之数组中出现次数超过一半的数字(九度OJ1370)

    题目描述: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2 ...

  9. 剑指Offer 28. 数组中出现次数超过一半的数字 (数组)

    题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. ...

随机推荐

  1. multipass指定virualbox搭建k8s集群(选择docker作为默认容器)

    目录 前言 步骤 初始化三台虚拟机 统一安装docker 修改docker镜像源 查看masterIP 安装master节点(重点设置) 查看master的token 安装worker节点 测试 部署 ...

  2. .Net Core 中的选项Options

    .NetCore的配置选项建议结合在一起学习,不了解.NetCore 配置Configuration的同学可以看下我的上一篇文章 [.Net Core配置Configuration源码研究] 由代码开 ...

  3. 羽夏笔记——PE结构(不包含.Net)

    写在前面   本笔记是由本人独自整理出来的,图片来源于网络.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你 ...

  4. Appium问题解决方案(4)- Error while obtaining UI hierarchy XML file: com.android.ddmlib.SyncException

    背景 操作步骤 运行 uiautomatorviewer.bat 点击左上角的 Device ScreensShot 报错 截图 解决方法 网上还是有很多方法的,可能造成的原因不同,我是第六种方法解决 ...

  5. Mysql常用sql语句(3)- select 查询语句基础使用

    测试必备的Mysql常用sql语句系列 https://www.cnblogs.com/poloyy/category/1683347.html 前言 针对数据表里面的每条记录,select查询语句叫 ...

  6. js简单化技巧

    1.交换两个变量而没有第三个 let x = 1;let y = 2;[x, y] = [y, x];console.log(x, y); 输出: 2 1 2.将数字转换为字符串 const num  ...

  7. 【noip1998】题解:2的幂次方

    思路:设递归函数dfs(x)用于输出x的幂次方 最容易的思路:0不输出,1输出为2(0),2输出2,剩下的递归执行. 每一次递归:例如7,拆分为4+3,先拆出最大的是2的次方的数出来,输出4,再把3分 ...

  8. HCNP Routing&Switching之路由控制、路由策略和IP-Prefix List

    前文我们了解了IS-IS路由聚合和认证相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15306645.html:今天我们来聊一聊路由控制技术中的路由策 ...

  9. 变着花样来接参,PHP中接收外部参数的方式

    对于PHP这样一个web语言来说,接参是非常重要的一个能力.毕竟从前端表单或异步请求传递上来的数据都要获取到才能进行正常的交互展示.当然,这也是所有能够进行web开发的语言的必备能力.今天我们就来看看 ...

  10. 数组转为unicode字符编码字符串

    json_encode($data, JSON_UNESCAPED_UNICODE)在创建微信卡券,发送数据时需要这个