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

简介: 题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。   看到这道题,我们马上就会想到,要是这个数组是排序的数组就好了。如果是排序的数组,那么我们只要遍历一次就可以统计出每个数字出现的次数,这样也就能找出符合要求的数字了。

 

题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。

 

看到这道题,我们马上就会想到,要是这个数组是排序的数组就好了。如果是排序的数组,那么我们只要遍历一次就可以统计出每个数字出现的次数,这样也就能找出符合要求的数字了。题目给出的数组没有说是排好序的,因此我们需要给它排序。排序的时间复杂度是O(nlogn),再加上遍历的时间复杂度O(n),因此总的复杂度是O(nlogn)

接下来我们试着看看能不能想出更快的算法。前面思路的时间主要是花在排序上。我们可以创建一个哈希表来消除排序的时间。哈希表的键值(Key)为数组中的数字,值(Value)为该数字对应的次数。有了这个辅助的哈希表之后,我们只需要遍历数组中的每个数字,找到它在哈希表中对应的位置并增加它出现的次数。这种哈希表的方法在数组的所有数字都在一个比较窄的范围内的时候很有效。本博客系列的第13就是一个应用哈希表的例子。不过本题并没有限制数组里数字的范围,我们要么需要创建一个很大的哈希表,要么需要设计一个很复杂的方法来计算哈希值。因此总体说来这个方法还不是很好。

前 面两种思路都没有考虑到题目中数组的特性:数组中有个数字出现的次数超过了数组长度的一半。也就是说,有个数字出现的次数比其他所有数字出现次数的和还要 多。

因此我们可以考虑在遍历数组的时候保存两个值:一个是数组中的一个数字,一个是次数。当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的 数字相同,则次数加1。如果下一个数字和我们之前保存的数字不同,则次数减1。如果次数为零,我们需要保存下一个数字,并把次数设为1。由于我们要找的数字出现的次数比其他所有数字出现的次数之和还要多,那么要找的数字肯定是最后一次把次数设为1时对应的数字

基于这个思路,我们不难写出如下代码:

 

#include<iostream>
using namespace std;

bool CheckMoreThanHalf(int *numbers, int length, int number);

int MoreThanHalfNumber(int *numbers, int length)
{
    if(numbers == NULL || length <= 0)
        return -1;
    
    int result = numbers[0];
    int times = 1;
    for(int i = 1; i < length; ++i)
    {
        if(times == 0)
        {
            result = numbers[i];
            times = 1;
        }
        else if(numbers[i] == result)
            times++;
        else
            times--;
    }
    
    if(!CheckMoreThanHalf(numbers, length, result))
        result = 0;
    
    return result;
}

bool CheckMoreThanHalf(int *numbers, int length, int number)
{
    int times = 0;
    for(int i = 0; i < length; ++i)
    {
        if(numbers[i] == number)
            times++;
    }
    
    bool isMoreThanHalf = true;
    if(times * 2 <= length)
    {
        isMoreThanHalf = false;
    }
    
    return isMoreThanHalf;
}

int main()
{
    int numbers[] = {1, 2, 3, 2, 2, 2, 5, 4, 2};
    int length = sizeof(numbers) / sizeof(int);
    
    cout<<MoreThanHalfNumber(numbers, length)<<endl;
    
    return 0;
}

 

 

 

 在上述代码中,有两点值得讨论:

(1)      我们需要考虑当输入的数组或者长度无效时,如何告诉函数的调用者输入无效。关于处理无效输入的几种常用方法,在本博客系列的第17中有详细的讨论;

(2)      本算法的前提是输入的数组中的确包含一个出现次数超过数组长度一半的数字。如果数组中并不包含这么一个数字,那么输入也是无效的。因此在函数结束前我还加了一段代码来验证输入是不是有效的。

 

来源:http://zhedahht.blog.163.com/blog/static/25411174201085114733349/

 

img_e00999465d1c2c1b02df587a3ec9c13d.jpg
微信公众号: 猿人谷
如果您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】
如果您希望与我交流互动,欢迎关注微信公众号
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

目录
相关文章
|
5月前
|
算法
面试题:如何找出数组里出现次数超过总数1/3的数
如果你每次从nums中拿出3个不一样的数作为一组,肯定会出现两种情况。一,nums被取空了,那么nums中每个数出现次数最多占总次数的1/3,写代码很好处理吧!! 二,还有剩余,这个情况就复杂了,有可能剩余多个,但是……但是,最多只可能剩余两种数。 为什么? 3个不同的数凑一组才能删掉,所以不可能删掉超过1/3的数。所以超过1/3的数肯定被剩下来,但是,剩下来的俩数并不一定都是超过1/3的,这点额外注意。
29 1
【剑指offer】-数组汇总出现次数超过一半的数字-27/67
【剑指offer】-数组汇总出现次数超过一半的数字-27/67
|
4月前
|
存储 机器学习/深度学习 C语言
Day3 字符串中找出连续最长的数字串、数组中出现次数超过一半的数字
Day3 字符串中找出连续最长的数字串、数组中出现次数超过一半的数字
28 0
|
9月前
1186:出现次数超过一半的数
1186:出现次数超过一半的数
|
10月前
剑指offer 40. 数组中出现次数超过一半的数字
剑指offer 40. 数组中出现次数超过一半的数字
45 0
|
10月前
剑指offer_数组---数组中出现次数超过一半的数
剑指offer_数组---数组中出现次数超过一半的数
32 0
|
C++
13.数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
39 0
|
算法 搜索推荐
数组中出现次数超过一半的数字(简单难度)
数组中出现次数超过一半的数字(简单难度)
94 0
|
算法
【刷算法】数组中出现次数超过一半的数字
【刷算法】数组中出现次数超过一半的数字