数组中出现次数超过一半的数字

数组中出现次数超过一半的数字

http://www.nowcoder.com/questionTerminal/e8a1b01a2df14cb2b228b30ee6a92163

描述

这是一篇针对初学者的题解。共用三种方法解决。
知识点:数组,排序,哈希
难度:一星


题解

题目抽象:给定一个数组,找出数组中的众数,若有,返回众数,若没有,返回0
众数定义:数组中出现次数大于数组一般的元素

方法一:哈希法

根据题目意思,显然可以先遍历一遍数组,在map中存每个元素出现的次数,然后再遍历一次数组,找出众数。

代码

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        unordered_map<int,int> mp;
        for (const int val : numbers) ++mp[val];
        for (const int val : numbers) {
            if (mp[val] > numbers.size() / 2 ) return val;
        }
        return 0;
    }
};

时间复杂度:O(n)
空间复杂度:O(n)

方法二:排序法

可以先将数组排序,然后可能的众数肯定在数组中间,然后判断一下。

代码

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        sort(numbers.begin(), numbers.end());
        int cond = numbers[numbers.size() / 2];
        int cnt = 0;
        for (const int k :numbers) {
            if (cond == k) ++cnt;
        }
        if (cnt > numbers.size() / 2) return cond;
        return 0;
    }
};

时间复杂度:O(nlongn)
空间复杂度:O(1)

方法三:候选法(最优解)

加入数组中存在众数,那么众数一定大于数组的长度的一半。
思想就是:如果两个数不相等,就消去这两个数,最坏情况下,每次消去一个众数和一个非众数,那么如果存在众数,最后留下的数肯定是众数。

具体做法:

  1. 初始化:候选人cond = -1, 候选人的投票次数cnt = 0
  2. 遍历数组,如果cnt=0, 表示没有候选人,则选取当前数为候选人,++cnt
  3. 否则,如果cnt > 0, 表示有候选人,如果当前数=cond,则++cnt,否则--cnt
  4. 直到数组遍历完毕,最后检查cond是否为众数

代码

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        int cond = -1;
        int cnt = 0;
        for (int i=0; i<numbers.size(); ++i) {
            if (cnt == 0) {
                cond = numbers[i];
                ++cnt;
            }
            else {
                if (cond == numbers[i]) ++cnt;
                else --cnt;
            }

        }
        cnt = 0;
        for (const int k :numbers) {
            if (cond == k) ++cnt;
        }
        if (cnt > numbers.size() / 2) return cond;
        return 0;
    }
};

时间复杂度:O(n)
空间复杂度:O(1)

全部评论
后面的验证其实没有必要的吧
1 回复 分享
发布于 2022-07-28 22:16
排完序直接取中间的数不是就了吗?还需要方法二那样加吗?
9 回复 分享
发布于 2021-06-21 21:13
候选人candidate,不是cond
8 回复 分享
发布于 2021-06-22 22:37
用栈也可以,当前值与栈顶相同,入栈。与栈顶不同,出栈。遍历完后。栈顶就是答案。
6 回复 分享
发布于 2022-09-25 00:57 广东
方法一中:可以在同一个循环里完成次数统计和众数次数是否大于数组长度一半的判断。
4 回复 分享
发布于 2020-07-11 21:56
只会方法1,想不到方法2,叹为观止方法3
3 回复 分享
发布于 2021-12-31 11:44
方法3中第二个循环根本没必要。题目求的是元素,不是个数。16行下面直接return cond就行了
3 回复 分享
发布于 2022-02-28 14:07
方法三有问题,对于数组vector<int> as={2,2,2,2,3,3,3,2,2,4,4,4};输出为0</int>
2 回复 分享
发布于 2021-03-31 12:01
方法三下面的一层循环是多余的吧,已经明确有结果了,最后能活下来的肯定是目标值
1 回复 分享
发布于 2022-05-30 23:23
方法三。时间复杂度2n吧。方法一时间可以优化成n
点赞 回复 分享
发布于 2021-01-16 17:02
方法三有问题,[1,2,3,2,4,2,5,2,3],结果为3
点赞 回复 分享
发布于 2021-04-20 11:45
能数学证明下方法三吗?
点赞 回复 分享
发布于 2021-07-23 23:25
方法二说的有问题。众数不一定在数组中间。如[1,2,3,4,5,6,6]。在此题下如果一个数组有超过一半的数字重复,那么确实众数在中间。总之说的不严谨,当然想到思路2还是厉害的。
点赞 回复 分享
发布于 2022-04-13 23:37
方法三你写复杂了: public class Solution { public int MoreThanHalfNum_Solution(int [] tmp) { int n = tmp.length; int num = -1, cnt = 0; for (int i = 0; i < n; i++) { if (tmp[i] == num) { cnt++; } else { if (cnt == 0) { num = tmp[i]; } else { cnt--; } } } return num; } }
点赞 回复 分享
发布于 2022-04-20 17:01
方法三是求众数的代码是有问题的,比如[2,4,3,4]这个数组,求得的众数是3,而不是4.
点赞 回复 分享
发布于 2022-07-10 11:33
排序法有问题,具体如下: 1.用sort空间复杂度就不会是o(1), 最坏为o(n) 2.既然答案是排序后的中间值,那为啥要完整排序呢,基于快排的topk(k为n/2)即可,时间复杂度可以降低到o(n)
点赞 回复 分享
发布于 2022-10-29 22:45 北京
次数超过一半,不是等于一半。
点赞 回复 分享
发布于 2023-02-12 22:06 广东
方法三惊讶我一百年
点赞 回复 分享
发布于 04-06 00:09 江苏

相关推荐

11-08 13:58
门头沟学院 Java
程序员小白条:竟然是蓝桥杯人才doge,还要花钱申领的offer,这么好的公司哪里去找
点赞 评论 收藏
分享
评论
172
17
分享
牛客网
牛客企业服务