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

剑指offer

Posted by chl on February 13, 2019

题目描述

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

解法

解法一:利用map来存储每个数字出现的次数,然后判断是否超过数组一半来返回;

解法二:基于数组特点,由于有超过数组长度一半的数值,所以该数值出现次数总和大于其他数值出现的总和,所以保存两个值result,ties,一个是数组中的一个数字,另一个是次数,当遍历到下一个数字的时候,如果和之前保存的数值相同,那么次数++,否则次数–,如果次数为0,则将当前遍历到的数值赋给result;最后剩下的result是出现次次数最多的数值,但是还要遍历检查一遍该数值是否满足出现次数为数组长度的一 半;

解法三:假设数组排好序,且求的数值出现次数超过数组长度的一半,那么中间位置的数字就是要求的数字;但是并不需要直接排好序,而是利用快排思想,每次随机取一个数值将数组分隔为两部分,然后判断当前取得数值的位置,如果为中间,则是要求的数字,否则判断是大于还是小于来重新快排;当然最后求出的中间位置的数字任要检查是否满足出现次数为数组长度的一半;

解法二代码

        if( numbers.size() == 0){
            return 0;
        }
        
        int num = numbers.size();
        int result = numbers[0];
        int times = 1;
        for(int i = 1;i < num;i++){
            if(times == 0){
                result = numbers[i];
                times++;
            }else if(numbers[i]==result){
                times++;
            }else{
                times--;
            }
        }
        
        int count = 0;
        for(int i = 0 ; i < num;i++){
            if(numbers[i]==result){
                count++;
            }
        }
        
        if(count > num/2){
            return result;
        }
        
        return 0;
    }