leetcode - [169]多數元素|刷题打卡

271 阅读3分钟

1. 题目描述

[169] 多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
    
示例 1:
输入: [3,2,3]
输出: 3
    
示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2
    
Related Topics 位运算 数组 分治算法

2. 思路分析

​ 看到这道题的时候,一开始有两个想法:

  1. 构造一个Map,然后遍历把值作为key,value是出现的次数,最后再遍历map得到目标值(method1)
    1. 我看上面有两次循环,就想着能不能省掉一个,于是有了method2
  2. 第二个想法是直接排序,排序完之后的数组,在 n/2 下标的位置,肯定是目标值(method3)
  3. 题目里面提到了能否一次循环,空间复杂度为1,一开始我是没有思路的,后面参考了LeetCode的解答,摩尔选举法。目标值肯定是超过其余数值的出现次数之和,因此,我们对值出现的次数,如果是相同就+1,不同就-1,如果为0做替换处理,那么留到最后的值,肯定是目标值(mehtod4)

3. AC代码

public class No169 {
    public int majorityElement(int[] nums) {
//        return method1(nums);
//        return method2(nums);
//        return method3(nums);
        return method4(nums);
    }

    /**
     * 最普通的思路,通过map记录每个数字出现的次数,然后选出最多的一个数
     *
     * 执行耗时:16 ms,击败了20.67% 的Java用户
     * 内存消耗:43.5 MB,击败了28.88% 的Java用户
     *
     * @param nums
     * @return
     */
    private int method1(int[] nums) {
        Map<Integer,Integer> map = new HashMap<Integer,Integer>();
        for (int i =0;i<nums.length;i++) {
            if(map.containsKey(nums[i])) {
                map.put(nums[i],map.get(nums[i])+1);
            } else {
                map.put(nums[i],1);
            }
        }

        int temp = 0;
        int re = 0;
        ;
        for(Map.Entry<Integer,Integer> entry: map.entrySet()) {
            if(entry.getValue() > temp) {
                re = entry.getKey();
                temp = entry.getValue();
            }
        }
        return re;
    }

    /**
     * 类似method1 天真的以为会比method1快
     *
     * 虽然循环少了,但是判断多了
     *
     * 执行耗时:23 ms,击败了5.77% 的Java用户
     * 内存消耗:43.3 MB,击败了30.73% 的Java用户
     *
     * @param nums
     * @return
     */
    private int method2(int[] nums) {
        Map<Integer,Integer> map = new HashMap<Integer,Integer>();
        int re = 0;
        int majorityElement = -1;

        for (int i =0;i<nums.length;i++) {
            int temp = 0;

            if(map.containsKey(nums[i])) {
                temp = map.get(nums[i])+1;
                map.put(nums[i],temp);
            } else {
                temp = 1;
                map.put(nums[i],temp);
            }

            if(temp > re) {
                re = temp;
                majorityElement = nums[i];
            }
        }
        return majorityElement;
    }

    /**
     * 多理解题,可以知道想要结果的数字,肯定会出现在 排序后的数组中间
     *
     * 执行耗时:2 ms,击败了69.62% 的Java用户
     * 内存消耗:41.8 MB,击败了48.27% 的Java用户
     *
     * @param nums
     * @return
     */
    public int method3(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length/2];
    }

    /**
     * 再次解析题目,因为多数元素的出现次数肯定大于其他所有元素的次数之和
     * 在遍历的时候,可以直接 +1 以及 -1
     *
     * 来自LeetCode解法 Java-3种方法(计数法/排序法/摩尔投票法) - 摩尔投票法
     *
     * 执行耗时:1 ms,击败了99.99% 的Java用户
     * 内存消耗:41.6 MB,击败了77.02% 的Java用户
     *
     * @param nums
     * @return
     */
    public int method4(int[] nums) {
        int cand_num = nums[0], count = 1;
        for (int i = 1; i < nums.length; ++i) {
            if (cand_num == nums[i])
                ++count;
            else if (--count == 0) {
                cand_num = nums[i];
                count = 1;
            }
        }
        return cand_num;
    }

4. 总结

​ 一开始做排序取值的时候,还没有细挖题目的信息,在想着把每个出现的值怎么统计以及做比对,很多时候,理解真的是拐个弯的事情


​ 本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情