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

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

描述:

        数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

        注:此处修改了牛客的条件,不一定存在数组中出现次数超过一半的数字。

        数据范围:n≤50000,数组中元素的值 :0≤val≤10000

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

解题方法:

 1、投票算法

        思路:

        数组中有n个元素,如果有一个元素出现的次数超过数组长度的一半,那么它的元素个数一定大于其他元素个数的总和,那么该元素的个数减去其他元素的个数一定是大于1的,此时若将数组中元素值不同的数相互抵消(即使每次都是使用次数超过一半的元素与其他元素进行抵消,更别说可能会有其他元素间相互抵消),那么剩下的数一定是元素出现的次数超过数组长度的一半。

        步骤:

        1、选择输入数组中第一个元素作为候选元素candidate,并设置其出现次数为count=1。

        2、遍历数组,当遇到与candidate相同的元素,count+1;遇到不同的元素,count-1。当count为0的时候,选择下一个元素为候选元素,并且置count=1。

        3、遍历到数组的最后,剩下的candidate就可能是数组中出现次数超过一半的数字。

        4、统计该candidate元素出现的次数,若超过一半则返回candidate;反之,返回0。  

      为什么还要判断元素出现的次数是否超过一半呢,不是留下的candidate一定是该元素吗?

        原因如下:

        如果存在某个元素个数超过数组一半的元素,那么candidate一定是该元素,前者是后者的充分条件,但是candidate存在,却不一定存在某个元素个数超过数组一半的元素,这只是充分不必要条件。如果数组为[1,3,6,3,4,3,3],[2,2,5,2,2,3,1,4,2,2],即数组中存在某个元素个数超过数组一半的数,那么剩下的candidate一定是该元素。但是如果现在的数组为[1,4,3,5,3,3],此时得到的candidate为3,但是我们可以看出元素3的个数刚好为数组的一半,并不满足条件,所以我们需要遍历一遍以此来统计元素个数,超过一半才满足。

        代码:

import java.util.*;
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        if(array == null || array.length < 1){
            return 0;
        }
        //第一个候选元素
        int candidate = array[0];
        int count = 1;
        //遍历数组
        for (int i = 1; i < array.length; i++) {
            //遇到相同元素,个数加1
            if (array[i] == candidate) {
                count++;
            }
            //遇到不同元素,个数减1 
            else {
                count--;
            }
            //当候选元素个数为0时,选取下一个元素为候选元素,计数为1
            if (count == 0) {
                candidate = array[++i];
                count++;
            }
        }
        //统计该元素在数组中出现的次数
        int num = 0;
        for(int i=0; i < array.length; i++)
            if(array[i] == candidate)
                num++;
        //超过一半则返回该元素,反之为0
        return (num > array.length/2)? candidate:0;
    }
}

        

2、哈希表计数法

        思路:

        首先我们想到的就是遍历一遍数组元素,并且在遍历过程中统计每一个元素出现的次数,然后再判断元素出现的次数是否大于数组长度的一半,如果超过,就返回该元素,如果未超过就继续遍历,直到数组遍历完全,此时还没有元素超过一半就返回0,过程中可以使用哈希表来存储。

        代码:

import java.util.*;
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        if(array == null || array.length < 1){
            return 0;
        }
        //辅助空间,存储元素值及其出现次数
        Map<Integer,Integer> mp = new HashMap<Integer,Integer>();
        for(int i = 0; i < array.length; i++){
            //元素存在map集合中,出现次数+1
            if(mp.containsKey(array[i])){
                mp.put(array[i],mp.get(array[i])+1);
            }
            //元素第一次出现,计数为1
            else{
                mp.put(array[i],1);
            }
            //判断当前元素出现的次数是否超过数组长度的一半
            if(mp.get(array[i]) > array.length / 2){
                return array[i];
            }
        }
        return 0;
    }
}

       时间复杂度:O(n),遍历一遍长度为n的数组

       空间复杂度:O(n),将长度为n的数组使用map集合进行存储

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值