算法题:剑指 Offer 39. 数组中出现次数超过一半的数字(题目+思路+代码+注释) 时空 1ms击败99.95%用户 一次AC

题目

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

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2

限制:

1 <= 数组长度 <= 50000

注意:本题与主站 169 题相同:https://leetcode-cn.com/problems/majority-element/

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

代码最少的AC办法(2行代码)

题目说有一个数的个数一定超过一半个数,那岂不是最中间的一定是那个数咯,那我们图简单直接排序取中值,确实能通过,耗时在2ms

由于排序过程的时间复杂度是Logn*n,我觉得并不是最快的,没有遵守算法的提前结束原则,肯定还有优化空间。

public int majorityElement2(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length / 2];
    }

自己实现简单堆统计(推荐)

耗时1ms 超过99.95%的人
查找和插入的过程没有对堆里数据做二分查找和排序,如果数据量大则可以优化查找和插入
假设数组长度为n,既然你说有一个数的数量大于了一半,那这个数组里最多有(n/2)+1个不一样的数。(不懂可以列6个数和7个数看一下就知道了)
那我就定义一个长度为(n/2)+1的数组来存数字,定义一个下标一一对应的数组来存计数。我存的过程中一旦发现某个数的计数已经超过了(n/2)则直接返回这个数即可。

public int majorityElement(int[] nums) {
        int mid = nums.length / 2;
        int[] numsCopy = new int[mid + 1];
        int[] count = new int[mid + 1];
        int index = 0, c = 0;
        boolean find;
        for (int i : nums) {
            find = false;
            //查
            for (int j = 0; j <= index; j++) {
                if (numsCopy[j] == i) {
                    c = count[j] = count[j] + 1;
                    find = true;
                    break;
                }
            }
            //插
            if (!find) {
                numsCopy[index] = i;
                c = count[index] = 1;
                index++;
            }
            if (c > mid) {
                return i;
            }
        }
        //代码不会到这来的,因为前面一定会返回
        return nums[0];
    }

摩尔投票法(推荐)

看题解看到的这个方法,确实很牛,但是我看了下时空和我上面的自定义堆效率是一样的,都是1ms和44M多的内存占用,没太大区别,但我还是觉得这个算法是最牛的。
既然你说你的数量是超过一半,那我就从第一个数开始,假设当前数就是对的那个数,下一个数跟当前数相等我就让票数加1,不相等就票数减一,一旦计数降到了0一下就换数到不同的这个数并重置计数器为0。当遍历完所有的数,坚持到最后的一定是那个多的数。

public int majorityElement(int[] nums) {
        int now = nums[0];
        int count = 0;
        for (int i : nums) {
            if (i == now) {
                count++;
            } else {
                count--;
                if (count <= 0) {
                    now = i;
                }
            }
        }
        return now;
    }

哈希法

耗时11ms,速度较慢。占用空间也更多,不建议使用。

public int majorityElement1(int[] nums) {
        int mid = nums.length / 2;
        HashMap<Integer, Integer> map = new HashMap<>(mid);
        for (int i : nums) {
            Integer count = map.get(i);
            if (count == null) {
                count = 1;
            } else {
                count += 1;
            }
            if (count > mid) {
                return i;
            }
            map.put(i, count);
        }
        return nums[0];
    }
posted @ 2022-02-17 17:56  HumorChen99  阅读(0)  评论(0编辑  收藏  举报  来源