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

题目描述

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

输入

[1,2,3,2,2,2,5,4,2]

返回

2

思路:数组中有一个数字出现的次数超过了数组长度的一半,如果把这个数组排序,那么排序之后位于数组中间的数字一定就是那个出现次数超过数组长度一半的数字。也就是说,这个数字就是统计学上的中位数,即长度为 n 的数组中第 n/2大的数字。我们有成熟的时间复杂度为O(n)的算法得到数组中任意第 K 大的数字。

这种算法受快速排序算法的启发。在随机快速排序算法中,我们现在数组中随机选择一个数字,然后调整数组中数字的顺序,使得比选中的数字小的数组都排在它的左边,大的排在右边,如果选中的数字的下标刚好是 n/2,那么这个数字就是数组的中位数;如果它的下标大于 n/2,那么中位数位于它的左边,我们可以继续在它的左边部分的数组中查找;如果下标小于 n/2,中位数位于它的右边,我们可以继续在它的右边查找,这是典型的递归过程。

 public int MoreThanHalfNum(int[] arr){
    if(arr == null)
        return 0;
     int len = array.length;
     int start = 0,end = len - 1;
     int mid = len / 2;
            while(start <= end){
            int index = partition(array,start,end);
            if(index == mid){
                int res = array[index];
                if(isMoreHalf(res,array)){
                    return res;
                }             
            }
            else if(index < mid){
                start = index + 1;
            }
            else{
                end = index - 1;
            }
        }
        return -1;
    }

}
//填坑法,初始选中第一个元素为第一个坑,向右开始遍历
public int partition(int[] arr, int left, int right){

    int i = left;
    int j = right;
    int key = arr[i];
    while(i < j){
        while(i < j && arr[j] >= key){
            j--;
        }
        arr[i] = arr[j];
        while(i < j && arr[i] <= key){
            i++;
        }
        arr[j] = arr[i];
    }
    arr[i] = key;//最后将key填入最后一个坑中(i=j)
    return i;
}

//验证数字result 是否超过一半
public boolean checkMoreThanHalf(int[] arr,int result){
    int times = 0;
    for(int i = 0;i < arr.length;i++){
        if(arr[i] == result){ 1222
            times++;
        }
    }
    boolean isHalf = true;
    if(times *2 <= arr.length){
        isHalf = false;
    }
    return isHalf;

}

解法二:候选法

加入数组中存在众数,那么众数一定大于数组的长度的一半。
思想就是:如果两个数不相等,就消去这两个数,最坏情况下,每次消去一个众数和一个非众数,那么如果存在众数,最后留下的数肯定是众数。

直接遍历数组,将数组的第一个元素直接赋值给 result当做超过数组的一半,并设置变量次数times为1,遍历过程中如果等于 result,次数times++,如果不等于则 times--,遍历到当前元素times=0时,则将当前元素arr[i]重新赋值给 result。

实现代码如下

public int MoreThanHalfNum(int[] arr){
    if(arr == null)
        return 0;
    int times = 1;
    int result = arr[0];
    for(int i = 1;i < arr.length;i++){
        if(times == 0){
            result = arr[i];
            times = 1;
        }
        else{
            if(arr[i] == result)
                times++;
            else{
                times--;
        }        
    }
    times = 0;
    for(int num : arr){
        if(result = num)
            times++;
    }
    if(times > arr.length/2){
        return result
    }
    return 0;

}

简洁的解法:

class Solution {
    public int majorityElement(int[] nums) {
        if(nums.length == 0) {
            return 0;
        }
        int candidate = 0;
        int count = 0;
        for(int num : nums) {
            if(count == 0){
                candidate = num;
            }
            count += (num == candidate) ? 1 : -1;
        }
        return candidate;

    }
}

参考:

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值