美文网首页
剑指Offer第39题——数组中出现次数超过一半的数

剑指Offer第39题——数组中出现次数超过一半的数

作者: wuhuaguo丶 | 来源:发表于2019-04-30 11:18 被阅读0次
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

可以先排序,排序之后,出现次数超过一半的数字肯定出现在中位数的位置,如果不考虑时间复杂度,可以将数组排序,然后取中间位置的数字。

public int MoreThanHalfNum_Solution(int [] array) {
       if (array == null || array.length == 0)
           return 0;
       Arrays.sort(array);
       int count = 0;
       int v = array[array.length / 2];
       for (int i : array) {
           if(i == v){
               count++;
           }
       }
       // 判断出现的次数到底是不是大于长度的一半 
       return count>array.length/2?v:0;
       
   }

但事实情况为必须要考虑时间复杂度,sort方法的时间复杂度为O(nlgn),复杂度太高。可以使用其他方法。
使用快速排序的切分法可以有效降低时间复杂度。时间复杂度为O(n)

    // 主方法
    public int moreThanHalfNum(int[] array) {
        if (array == null || array.length == 0)
            return 0;

        int mid = select(array, array.length / 2);
        return checkMoreThanHalf(array, mid);
    }
    /**
     * 快速排序的切分方法
     */
    private int partition(int[] array, int low, int high) {
        int i = low;
        int j = high + 1;
        int v = array[low];
        while (true) {
            // 拿low+1之后的与low比较,找到比low大的
            while (array[++i] < v) {
                // 左侧指针指到了最右侧
                if (i == high)
                    break;
            }
            // 拿high之前的与low比较,找到比low小的
            while (array[--j] > v) {
                // 右侧指针指到了最左侧
                if (j == low)
                    break;
            }
            // 两个指针相遇
            if (i >= j) {
                break;
            }
            // 交换i与j的位置,相当于按照大小调换
            swap(array, i, j);
        }
        // 跳出循环证明已经将小的移到了左边,大的移到了右边,交换low与j的位置,实现low的位置正确
        swap(array, low, j);
        return j;
    }
    /**
     * 选择排名为k的元素,只是部分排序,时间复杂度为O(N)
     */
    private int select(int[] array, int k) {
        int low = 0;
        int high = array.length - 1;
        // high==low时只有一个元素,不切分
        while (high > low) {
            int j = partition(array, low, high);
            // 如果j==k,说明找到了排名为k的元素,即为array[j]
            if (j == k)
                return array[k];
            // 如果j>k,说明找到的这个数的顺序太靠后,j后面都是比k大的,需要往前找,类似于二分法
            else if (j > k)
                high = j - 1;
            // 如果j<k,说明找到的这个数的顺序太靠前,j前面都是比k小的,需要往后找,类似于二分法
            else if (j < k)
                low = j + 1;
        }

        return array[k];
    }
    /**
     * 统计中位数是否超过数组元素个数的一半,若没有默认返回0
     */
    private int checkMoreThanHalf(int[] array, int number) {
        int count = 0;
        for (int a : array) {
            if (a == number)
                count++;
        }

        return count > array.length / 2 ? number : 0;
    }

相关文章

网友评论

      本文标题:剑指Offer第39题——数组中出现次数超过一半的数

      本文链接:https://www.haomeiwen.com/subject/yudmnqtx.html