169. 多数元素(剑指 Offer 39. 数组中出现次数超过一半的数字)

题目:

思路:

【1】利用排序来完成,优先将数组排序,那么数组中间的值肯定是存在最多的元素。【但是由于考虑到最优的排序算法的时间复杂度也是O(N*longN),其实不满足进阶条件,但是可以解决问题】

【2】利用额外的存储空间来解决,也就是使用Map来进行存储数值,然后将超过半数的那个元素拿出来。【这种虽然时间复杂度降了下来,但是空间复杂度却又上了去,而且这种空间换时间的方式其实也是比较推荐用于对时间要求很高,但是对空间要求不大的,毕竟用完了回收就好,只要不爆掉内存】

【3】基于进阶的考虑,其实摩尔投票法是最合适的。【也就是每两个不相同的数就会抵消,那么其实就只需要循环一次这个数组,且不太需要设置变量的额外空间】

假设数组中每个不同的数字就代表一个国家,而数字的个数就代表这个国家的人数,他们在一起混战,就是每两个两个同归于尽。我们就可以知道那个人数大于数组长度一半的肯定会获胜。

就算退一万步来说,其他的所有人都来攻击这个人数最多的国家,他们每两个两个同归于尽,最终剩下的也是那个众数

 

代码展示:

利用排序的方式:

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

利用额外空间的方式【正常的思维会是存完所有数据再去找,但其实没这个必要,因为目的是找超过半数的元素,只要找到了就可以停下来,进行返回了;如,100个中有80个相同的,但是只要找到第51个其实便可以停下来了,因为已经确认了这个元素就是超过半数的元素,后面的遍历便是浪费时间,变得不重要了】:

public int majorityElement(int[] nums) {
    Map<Integer, Integer> counts = new HashMap<>();
    int length = nums.length;
    for (int i = 0; i < length; i++) {
        int count = counts.getOrDefault(nums[i], 0) + 1;
        //如果某个数字出现的个数已经超过数组的一半,自己返回
        if (count > length / 2)
            return nums[i];
        counts.put(nums[i], count);
    }
    return -1;
}

进阶条件下利用摩尔投票法:

public int majorityElement(int[] num) {
    int major = num[0];
    int count = 1;
    for (int i = 1; i < num.length; i++) {
        if (count == 0) {
            //前面都消完了,在重新赋值
            count++;
            major = num[i];
        } else if (major == num[i]) {
            //自己人,count就加1
            count++;
        } else {
            //不是自己人就同归于尽,消掉一个
            count--;
        }
    }
    return major;
}

 

posted @ 2023-02-13 17:27  忧愁的chafry  阅读(3)  评论(0编辑  收藏  举报