剑指Offer:面试题29——数组中出现次数超过一半的数字(java实现)

来源:互联网 发布:淘宝的免费开店是什么 编辑:程序博客网 时间:2024/06/06 00:10

PS:在前几天的面试中,被问到了这个题。然而当时只能用最低效的方法来解。

更新:抱歉各位,这里好多代码并没有得到验证,可能有错.大家慎入坑.

问题描述:

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

思路1:

低效的做法:直接用哈稀表来存储<key, value>,并找出出现次数value大于等于一半的那个key。

代码:

import java.util.Map;import java.util.HashMap;public class Solution {    boolean InvalidInput = false;    public int MoreThanHalfNum_Solution(int [] array) {        if(array == null || array.length == 0){            InvalidInput = true;            return 0;        }        Map<Integer, Integer> map = new HashMap<Integer, Integer>();        int max = -1;        int ind = -1;        for(int i = 0; i < array.length; i++){            if(!map.containsKey(array[i])){                map.put(array[i], 1);            }else{                map.put(array[i], map.get(array[i])+1);            }            if(max < map.get(array[i])){                max = map.get(array[i]);                ind = array[i];            }        }        if(max > array.length/2){            return ind;        }else{            return 0;        }    }}

思路2:

—由于出现的次数超过了数组的一半,那么如果我们将数组排序,中间的那个数一定是要求的数字(前提是它一定存在)
—这里排序时采用快排的基本思想,随机选择一个数,调整数组使得它左边的数都小于它,右边的数都大于它。(参考Partition函数)(下一篇博客的代码中给出了关于Partition函数详细的注释)

import java.util.Map;import java.util.HashMap;public class Solution {    static boolean InvalidInput = false;    public int MoreThanHalfNum_Solution(int [] array) {        if(array == null || array.length == 0){            InvalidInput = true;            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;                index = 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;        int length = array.length;        for(int i = 0; i < length; i++){            if(array[i] == number){                times++;            }        }        boolean isMoreThanHalf = true;        if(times * 2 <= length){            InvalidInput = true;            isMoreThanHalf = false;        }        return isMoreThanHalf;    }    public static int Partition(int[] array, int start, int end){        if(array == null || array.length == 0 || start < 0 || end < 0){            InvalidInput = true;            return -1;        }        int index = RandomInRange(start ,end);        int tmp = array[index];        array[index] = array[end];        array[end] = tmp;        int small = start - 1;        for(index = start; index < end; index++){            if(array[index] < array[end]){                small++;                if(small != index){                    int temp = array[index];                    array[index] = array[small];                    array[small] = temp;                }            }        }        small++;        tmp = array[small];        array[small] = array[end];        array[end] = tmp;        return small;    }    public static int RandomInRange(int s, int e){        int Min = s;        int Max = e;        int result = Min + (int)(Math.random() * ((Max - Min) + 1));        return result;    }}

思路3:

根据数组特点找出O(n)的算法
1.数组中有一个数字出现的次数超过数组长度的一半,也就是说它出现的次数比其他所有的数字出现的次数的和还要多。
2.因此我们可以考虑在遍历数组的时候保存两个值:一个是数组中的一个数字,一个是次数。
3.当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的数字相同,则次数加1,否则减1.

代码:

import java.util.Map;import java.util.HashMap;public class Solution {    static boolean InvalidInput = false;    public int MoreThanHalfNum_Solution(int [] array) {        if(array == null || array.length == 0){            InvalidInput = true;            return 0;        }        int result = array[0];        int times = 1;        for(int i = 1; i < array.length; i++){            if(times == 0){                result = array[i];                times = 1;            }else if(array[i] == result){                times++;            }else{                times--;            }        }        if(!CheckMoreThanHalf(array, result)){            InvalidInput = true;            result = 0;        }        return result;    }   public static boolean CheckMoreThanHalf(int[] array, int number){        int times = 0;        int length = array.length;        for(int i = 0; i < length; i++){            if(array[i] == number){                times++;            }        }        boolean isMoreThanHalf = true;        if(times * 2 <= length){            InvalidInput = true;            isMoreThanHalf = false;        }        return isMoreThanHalf;    }}

PS:检查出现频率最高的是否超过一半,也还是需要遍历一次数组的。

1 1
原创粉丝点击