数组中出现次数超过一半的数字(java版)

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


【解题思路1】
先来看一种最简单的解法,算法复杂度为O(n*log(n))
//1.对数组进行排序,然后遍历
//2.遍历过程中,记录当前元素的出现次数,若超过数组长度的一半,即返回该值
//3.若遍历到最后也没有发现符合条件的元素,按照题目要求,返回 0
【源码1】

import java.util.Arrays;
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        if(array.length == 0){
            return 0;
        }
        Arrays.sort(array);
        boolean flag = false;
        int mNum=array[0], sum=0, temp=array[0], len=array.length/2;
        for(int a: array){
            if(a == temp){
                sum++;
                mNum = a;
            }
            if(sum > len ){
                flag = true;
                break; 
            }
            if(a != temp){

                sum = 1;
                temp = a;
            }
        }
        if(flag == false){
            mNum = 0;
        }
        return mNum;
    }
}

a. sum用来记录当前值出现的次数。若出现当前值变化的情况,需要重置sum=1 , 注意此时sum为1,不为0。
b. 设置标志位flag,是针对遍历到最后并没有发现符合条件的值的情况。


【解题思路2】在 “思路1” 的基础上做一个小小的改进。
//1.对数组进行排序
//2.假设存在出现次数超过一半的数字target,则其位于中位数的位置上。此时,无论中位数为单个数值,还是为两个数值的平均数,都为该值。因为若数组长度为偶数,中位数取中间两个值的平均数,此时两个值应该是相同的,都等于最后要求的这个数字target。
//3.求得target后,对数组进行一次遍历,计算target出现的次数,若超过一半则返回该值。否则,不存在符合条件的值,返回0。
【源码2】

import java.util.Arrays;

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        Arrays.sort(array);
        int count=0, len=array.length;
        for(int i=0;i<len;i++){
            if(array[i]==array[len/2]){
                count++;
            }
        }
        if(count>len/2){
            return array[len/2];
        }else{
            return 0;
        }  
    }
}

【解题思路3】最简单直观的考虑。分别计算每个元素出现的次数,取最大值与len/2做比较。时间复杂度为O(n)。
//1.使用hashmap

链接:https://www.nowcoder.com/questionTerminal/e8a1b01a2df14cb2b228b30ee6a92163
来源:牛客网

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
        for(int i=0;i<array.length;i++){
            if(!map.containsKey(array[i])){
               map.put(array[i],1); 
            }else{
                int count = map.get(array[i]);
                map.put(array[i],++count);
            }
        }
        Iterator iter = map.entrySet().iterator();
        while(iter.hasNext()){
            Map.Entry entry = (Map.Entry)iter.next();
            Integer key =(Integer)entry.getKey();
            Integer val = (Integer)entry.getValue();
            if(val>array.length/2){
                return key;
            }
        }
        return 0;
}

a. 使用迭代器iterator,加快遍历速度。


【解题思路4】该思路来自剑指offer的解法二,称为“打擂法”,也叫“守阵地思想”。若数组中有一个数字出现次数超过一半,则它出现的次数超过了其他所有数字出现次数的总和。算法复杂度为O(n)。
//1. 遍历数组,同时维护两个值:一个是数组中的一个元素e,另一个是次数count。
//2. 遍历过程中,若下一个元素和之前保存的e不相同,则次数count-1。若相同,则count+1。
//3. 若出现次数为零的情况,则e需要存储下一个数字,并把次数count=1。
//4. 若存在符合条件的元素,最后一次把次数置为1的数字即要找的目标值。否则,返回0。
//5. 验证最后维护的元素e,出现次数是否超过一半。

【源码4】

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        int length=array.length;
        if(array==null||length<=0){
            return 0;
        }
        int result=array[0];
        int times=1;
        for(int i=1;i<length;i++){
            if(times==0){
                result=array[i];
                times=1;
            }else{
                if(array[i]==result){
                    times++;
                }else{
                    times--;
                }
            }
        }
        times=0;
        for(int i=0;i<length;i++){
            if(result==array[i]){
                times++;
            }
       }

       if(times*2<length){
           result=0;
       }
       return result;
    }
}

【解题思路5】该思路来自剑指offer第一种解法。该解法会改变原数组。
//1. 若有一个数字出现次数超过了一半,则排序之后位于数组中间的那个数字就是要求的值。
//2. 在随机快速排序算法中,先在数组中随机选一个数字,调整数组中数字的顺序。使得比选中的数字小的数位于其左边,比选中的数字大的数字位于其右边。
//3. 如果这个选中的数字的下标刚好是n/2,则这个数字就是数组的中位数。如果它的下标比n/2大,则中位数应该位于其左边,继续在左边查找。如果它的下标比n/2小,则中位数应位于其右边,继续在右边查找。

【源码5】

链接:https://www.nowcoder.com/questionTerminal/e8a1b01a2df14cb2b228b30ee6a92163
来源:牛客网

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {  
        if(array==null||array.length==0)
            return 0;  
        int middle=array.length>>1;  
        int start=0;  
        int end=array.length-1;  
        int index=Partition(array,start,end);  
        while(index!=middle){  
            if(index>middle){  
                end=index-1;  
                ndex=Partition(array,start,end);  
            }else{  
                start=index+1;  
                index=Partition(array,start,end);  
            }
        }  
        int result=array[middle];  
        if(!CheckMoreThanHalf(array,result))
            result=0;
        return result;  
   }  

   public static boolean CheckMoreThanHalf(int array[],int number){  
        int times=0;  
        for(int i=0;i<array.length;++i){  
            if(array[i]==number)  
            times++;  
        }  
        boolean isMoreThanHalf=true;  
        if(times*2<=array.length){  
            isMoreThanHalf=false;  
        }  
        return isMoreThanHalf;  
  }  

    public static int Partition(int array[],int start,int end){  
        int pivotkey=(int)start+(int)Math.random()*(end-start);  
        while(start<end){  
            while(start<end&&array[end]>=array[pivotkey])  
                end--;  
            int temp=array[start];  
            array[start]=array[end];  
            array[end]=temp;  
            while(start<end&&array[start]<=array[pivotkey])  
                start++;  
            temp=array[start];  
            array[start]=array[end];  
            array[end]=temp;  
        }  
        return start;  
    }  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值