剑指offer - 28数组中出现次数超过一半的数字

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

思路有下面几种:

1. 使用一个map结构,保存所有数字出现的次数。

2. 排序的思想,如果是一个已排序的数组, 其中有长度超过一半的元素,则一定是数组中间的元素,先排序,再判断中间的元素个数是否超过数组长度的一半。

3. 打擂台的思想, 数组中同时去掉两个不同的数,最后剩下的就是结果

代码如下:

class Solution {
public:
    //方法一:如果是已排序的数组, 如果有一个数字个数大于长度的一半,则一定是数组中间的数字
    //      所以先将数组排序,然后取中间的数字,判断出现的个数是否大于一半
    int get_more_than_halfnum_sort(vector<int>& numbers){
        sort(numbers.begin(), numbers.end());
        int cnt = 0;
        int mid = numbers.size()/2;
        for(int i = 0; i < numbers.size(); ++i){
            if(numbers[i] == numbers[mid]){
                cnt++;
            }
        }
        return cnt > mid ? numbers[mid] : 0;
    }
    //方法二:打擂台的思想,设想数组的所有元素在一个擂台上, 
    //       如果有一个数字个数大与一半,则其可以1:1的将值不同的元素PK出去,剩下一个以上的胜利者值相同
    //       反过来,数组元素一个一个的上擂台,如果第一个和第二和值不同,则两个同时下台,
    //       如果两个值相同,则守擂人数加1
    //       最后守擂的就可能是个数超过一半的(少数派可能会内耗...)
    int get_more_than_halfnum_pk(vector<int>& numbers){
        if(0 == numbers.size()){
            return 0;
        }
        int cnt = 1;
        int num = numbers[0];
        for(int i = 1; i < numbers.size(); ++i){
            if(0 == cnt){       //如果擂台是空的,则当前元素上台
                num = numbers[i];
                cnt = 1;
            }
            else{               //擂台不空 则值相同则+1 不同则-1(两个同时下台)
                cnt = (num == numbers[i]) ? cnt+1 : cnt-1;
            }
        }
        if(0 == cnt){           //最后台上一个都没有了,则肯定没有超过一半的元素
            return 0;
        }
        else{
            cnt = 0;
            for(int i = 0; i < numbers.size(); ++i){
                if(numbers[i] == num){
                    cnt++;
                }
            }
            return cnt > numbers.size()/2 ? num : 0;
        }
    }
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        //return get_more_than_halfnum_sort(numbers);
        return get_more_than_halfnum_pk(numbers);
    }
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值