前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数组中出现次数超过一半的数字

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

作者头像
砖业洋__
发布2023-05-06 19:26:19
1450
发布2023-05-06 19:26:19
举报
文章被收录于专栏:博客迁移同步博客迁移同步

题目描述

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

题目链接:https://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163?tpId=13&tqId=11181&tPage=2&rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

方案一:

简单来想,就像游戏一样,5V5打平局,5V4就人数多的获胜,每个人都有属于自己的队伍,如果某支队伍超过了总人数一半就会获胜(这就是最后的检查环节)。也就是如果有2支队伍,一共9个人,遇到A队伍就++, 遇到B队伍就--,那么最后一个剩下的人,属于哪个队,哪个队的人数就多。本题也一样,最后一个剩下的数,很可能代表它的总数超过了一半,但是需要检查,等会讲为什么检查。

假设只有2支队伍,一共9个人,每组2个人pk,我们一一询问他们是哪个队伍的,以第一个人为例array[0],array[0]和array[1]pk,如果是同一支队伍就++count,表示队伍多了1个人,如果不相等就抵消,最后剩下的的那个人属于哪只队伍就获胜,比如

5,4,4,5,4,5,4,5,4

(54)(45)(45)(45)(4)

那么4超过了总数的一半。或者有很多队伍,有一只队伍超过的人数的一半,其余的混合队伍组合

比如5,1,5,2,5,3,5,4,5

(51)(52)(53)(54)(5)

那么5超过了队伍的一半

再来谈谈为什么需要检查?

1,2,3,4,5,6,7,8,9

(12)(34)(56)(78)(9),但是9出现次数并没有超过数组长度的一半,所以需要检查多的那个数是否超过数组长度的一半。

又比如

5, 1, 5, 2, 4, 3, 6, 7, 5

(51)(52)(43)(76)(5)最后留下了5,但是5出现次数并没有超过数组长度的一半,不符合。

​public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        if (array == null || array.length == 0)    return 0;
        if (array.length == 1)    return array[0];
        int len  = array.length;
        int count = 1;
        int res = array[0];
        for (int i = 1; i < len; ++i) {
            if (count == 0) {
                res = array[i];
                count = 1;
            } else if (res == array[i]) {
                ++count;
            } else {
                --count;
            }
        }
        return check(array, res) ? res : 0;
    }
    private boolean check(int[] arr, int res) {
        int len = arr.length;
        int count = 0;
        for (int i = 0; i < len; ++i) {
            if (arr[i] == res) {
                ++count;
            }
        }
        return (count << 1) > len ? true : false;
    }
}

方法二:基于快排思想

如果一个排过序的数组,那么超过数组一半长度的数字,一定位于中间,反之不一定,需要检查,这个数字也就是统计学上的中位数。比如[1, 2, 2], [1, 3, 3, 3]超过长度一半的一定位于中间,又比如[1, 2, 3]位于中间的不一定超过长度一半。

先在数组中随机选一个数字,然后调整数组中数字顺序,使得比选中的数字小的数字都排在它的左边,比选中的数字大的数字都排在它的右边,这也是快排思想。

如果我们选中的数字是数组的中位数,下标正好是n/2,那么在排序的过程中,如果下标小于n/2,那么中位数位于它的右边,如果下标大于n/2,那么中位数位于它的左边,过程用递归实现。直至下标正好是中位数,那么左边的数字比它小,右边的数字比它大,虽然还没有完全有序,但是已经足够了。继续左右递归这个过程是可以变成完全有序的,可以继续排序,但没必要。此时中间的数字出现次数一定超过了数组长度的一半(当然需要检查,原因同方案一)。

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        if (array == null || array.length == 0)    return 0;
        if (array.length == 1)    return array[0];
        int mid = array.length >> 1;
        int start = 0;
        int end = array.length - 1;
        int index = partition(array, start, end);
        while (index != mid) {
            if (index < mid) {
                start = index + 1; // 有序的中位数在右边区间
            } else {
                end = index - 1;
            }
            index = partition(array, start, end);
        }
        return check(array, index) ? array[index] : 0;
    }
    private boolean check(int[] arr, int index) {
        int len = arr.length;
        int count = 0;
        for (int i = 0; i < len; ++i) {
            if (arr[i] == arr[index]) {
                ++count;
            }
        }
        return (count << 1) > len ? true : false;
    }
    private int partition(int[] arr, int start, int end) {
        int i = start, j = end + 1;
        int compareNum = arr[start];
        while (true) {
            while (arr[++i] < compareNum) {
                if (i >= end)    break;
            }
            while (compareNum < arr[--j]) {
                if (j <= start)    break;
            }
            if (i >= j)    break;
            swapNum(arr, i, j);
        }
        swapNum(arr, start, j);
        return j;
    }
    private void swapNum(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

这种方法会改变原来的数组顺序,如果可以更改数组顺序,那么这一种方案是可行的。

方案一和方案二时间复杂度都是O(n)

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-12-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目描述
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档