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

原题

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

leetcode 上的原题

方法一

  • 由于是一半以上,所以排序后数组的中位数必定是我们所要的值。
public int majorityElement(int[] nums) {
    Arrays.sort(nums);
    return nums[nums.length/2];
}

结果:运行时长 2ms 内存消耗43.2MB。

方法二

  • 通过HashMap 来临时存储,并且每次更新出现的最多次数以及对应的数字
public int majorityElement(int[] nums) {
    Map<Integer,Integer> map=new HashMap<Integer,Integer>();
    int max=1,val,num=nums[0];
    for(int i=0,len=nums.length;i<len;i++){
        if(map.containsKey(nums[i])){
            val=map.get(nums[i])+1;
            map.put(nums[i],val);
            if(max<val){
                max=val;
                num=nums[i];
            }
        }
        else{
            map.put(nums[i],1);
        }
    }
    return num;
}

结果:运行时长 17ms 内存消耗45.2MB。

方法三

  • 根据快排选取的数必定通过一次更新必定在最终位置上。所以每次取排序部分的第一个数作为比较对象,然后看它的最终位置上是否在mid处,不在的话缩小范围。
public int majorityElement(int[] nums) {
    int len=nums.length,mid=len/2,pos=-1;
    int from=0,to=len-1;
    while(pos!=mid){
        pos=quickSort(nums,from,to);
        if(pos>mid)to=pos-1;
        else if(pos<mid)from=pos+1;
    }
    return nums[mid];
}
public int quickSort(int []f,int from,int to){
    if(from==to)return from;
    int p=from,q=to,head=f[from];
    while(p<q){
        while(p<q&&f[q]>=head)q--;
        f[p]=f[q];
        while(p<q&&f[p]<=head)p++;
        f[q]=f[p];
    }
    f[q]=head;
    return q;
}

结果:运行时长 677ms 内存消耗43.4MB。

方法四

  • 反思了一下,我觉得可能是原有数据有序,导致重复多次,所以我采用了随机选取基数
public int majorityElement(int[] nums) {
        int len=nums.length,mid=len/2,pos=-1;
        int from=0,to=len-1;
        while(pos!=mid){
            pos=quickSort(nums,from,to);
            if(pos>mid)to=pos-1;
            else if(pos<mid)from=pos+1;
        }
        return nums[mid];
    }
    public int quickSort(int []f,int from,int to){
        if(from==to)return from;
        int pos=(int)(Math.random()*(to-from));
        int temp=f[from];
        f[from]=f[pos+from];
        f[pos+from]=temp;
        int p=from,q=to,head=f[from];
        while(p<q){
            while(p<q&&f[q]>=head)q--;
            f[p]=f[q];
            while(p<q&&f[p]<=head)p++;
            f[q]=f[p];
        }
        f[q]=head;
        return q;
    }

结果:运行时长 74ms 内存消耗43.3MB。

方法五

  • 然后,我觉得还能优化,百度了一下,快排还有三者取中选择枢轴数的优化,我也试了一下
    三者取中选择枢轴数的优化:就是头,尾,中间数三个排序后的中间那个数作为基数。
public int majorityElement(int[] nums) {
        int len=nums.length,mid=len/2,pos=-1;
        int from=0,to=len-1;
        while(pos!=mid){
            pos=quickSort(nums,from,to);
            if(pos>mid)to=pos-1;
            else if(pos<mid)from=pos+1;
        }
        return nums[mid];
    }
    public int quickSort(int []f,int from,int to){
        if(from==to)return from;
        int mid=(from+to)>>1;
        if((f[from]<=f[mid]&&f[mid]<=f[to])||(f[to]<=f[mid]&&f[mid]<=f[from]))
            swap(f,from,mid);
        else if((f[mid]<=f[from]&&f[from]<=f[to])||(f[to]<=f[from]&&f[from]<=f[mid])){}
        else 
            swap(f,to,from);
        
        int p=from,q=to,head=f[from];
        while(p<q){
            while(p<q&&f[q]>=head)q--;
            f[p]=f[q];
            while(p<q&&f[p]<=head)p++;
            f[q]=f[p];
        }
        f[q]=head;
        return q;
    }
    public void swap(int f[],int a,int b){
        int temp=f[a];
        f[a]=f[b];
        f[b]=temp;
    }

结果:运行时长 10ms 内存消耗43MB。

心累,再怎么优化都没一开始想到的快。

在这里插入图片描述

方法六(官方的牛皮解法:投票法)

 public int majorityElement(int[] nums) {
    int x = 0, votes = 0;
    for(int num : nums){
        if(votes == 0) x = num;
        votes += num == x ? 1 : -1;
    }
    return x;
}

结果:运行时长 2ms 内存消耗43MB。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值