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

问题

题目:[数组中出现次数超过一半的数字]

思路

朴素的就不说了,这个打擂法倒是第一次见,反正我没有看见可以讲的很清楚的为什么这么做可以。
主要参考[数组中出现次数超过一半的数字 -java]

说下我的理解吧,打擂法的基本操作如下:
result = nums[0], 保存当前数字。count = 1, 按照如下的方式计数。
1. 当遍历到下一个数字时,如果这个数字跟之前保存的数字相同,则次数加1。
2. 如果不相同,则减1。“同归于尽”。
3. 如果count = 0, 则重新设置result = nums[i], count = 1.

如果数组中存在超过元素出现次数一半的元素,那么打擂法最后一次对result进行置位的nums[i]就是所求。如果,不存在则不是。

举个例子:先说存在的情形,由于是存在的,数组之间的顺序不是很重要,那么我们考虑两种极端的情形。
nums = [1,2,3,1,1];
第一种:nums = [1,1,1,2,3],这种情况可以找出来,因为出现次数count不会为0.
第二种:nums = [1,2,1,3,1],最后count = 1, nums[i] = 1,也恰好能找出来。
但是,nums = [1,2,3,4,5],显然和上面结果一样,但是5不是,所以还需验证。

代码

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        int sz = numbers.size();
        if(!sz) return 0;

        int result = numbers[0];
        int count = 1;

        for(int i = 1; i < sz; ++i){
            if(!count){
                result = numbers[i];
                count = 1;
            }else{
                if( numbers[i-1] == numbers[i] ) ++count;
                else count--;
            }
        }

        int cnt = 0;
        for( int i = 0; i < sz; ++i ){
            if( numbers[i] == result ) ++cnt;
        }
       return (cnt > sz/2)?result:0;
    }
};

思路1

假设存在的情况下,中间的元素肯定就是所求元素。但是,还有不存在的情形,此时再判断以下即可。可以先排序,再判断。

当然,先排序的话需要用到排序函数,时间复杂度会超过o(N).
所以,采用另外的方法,其实就是把中位数找出来。

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        int sz = numbers.size();
        if( !sz ) return 0;

        int result = min_index(numbers);
        int cnt = 0;
        for( int i = 0; i < sz; ++i ){
            if( result == numbers[i] ) ++cnt;
        }
        return (cnt > sz/2)?result:0;
    }
private:
    int partition( vector<int>& arr, int low, int high ){
        int i = low;
        int j = high;
        while( i < j ){
            while( i < j && arr[i] <= arr[j] ) --j; // right slide scan
            if(i < j){
                std::swap(arr[i], arr[j]); // rearrage the pivot to right slide
                ++i;
            }
            while( i < j && arr[i] < arr[j] ) ++i; // left slide scan
            if(i < j){
                std::swap(arr[i], arr[j]); // rearrage the pivot to left slide
                --j; 
            }
        }
        return i;
    }
private:
    int min_index( vector<int>& arr ){ // 获得中位数
        int low = 0;
        int high = arr.size() - 1;
        if( high < low ) return -1;

        int mid = arr.size()/2;

        int pos = partition(arr, 0, arr.size() - 1);
        while(pos != mid){
            if( pos < mid ) pos = partition( arr, pos+1, high );
            else pos = partition( arr, low, pos - 1 );
        }
        return arr[mid];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值