zoukankan      html  css  js  c++  java
  • LeetCode总结 169多数元素和面试17.10 主要元素

    LeetCode总结 169多数元素和面试17.10 主要元素


    这两道题都可以使用Boyer-Moore 投票算法。先说169简单题

    169. 多数元素

    题目:

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

    解题思路

    注意这里指的给定的数组总是存在多数元素,换句话说,测试用例中不可能出现【1,2,3】这样的例子。

    解法一

    最简单的是先排序,然后直接return数组的中间元素即可。就是求中位数的算法。

    class Solution {
        public int majorityElement(int[] nums) {
            Arrays.sort(nums);
            return nums[nums.length/2];
        }
    }
    
    解法二

    使用Boyer-Moore 投票算法。

    Boyer算法基本思想:在每一轮投票过程中,从数组中删除两个不同的元素,知道投票过程无法继续位置,此时数组为空或者数组剩下的元素都相等。

    说白点,就是抵消算法。知乎上讲的通俗明白,也就是刚开始的第一个数记为答案数或者成为candidate,然后设置更新状态count,开始遍历数组,当数组中接下来的数是candidate的话,count++,如果不是的话,就减减。到最后剩下的肯定就是数组中最多的数。

    标准的leetcode解释:

    Boyer-Moore 投票算法的步骤如下:

    1. 维护一个候选主要元素 candidate 和候选主要元素的出现次数 count,初始时 candidate 为任意值,count=0;
    2. 遍历数组 nums 中的所有元素,遍历到元素 x 时,进行如下操作:
      1. 如果count==0,将x赋值给candidate,否则不更新candidate值
      2. 如果x=candidate,则将count++,否则count--
    3. 遍历结束之后,如果数组nums中存在主要元素,则candidate为主要元素,否则candidate为数组的任意一个数字。

    代码:

     public int majorityElement(int[] nums) {
            int count = 0;
            Integer candidate = null;
            for (int num : nums) {
                if (count == 0) {
                    candidate = num;
                }
                count += (num == candidate) ? 1 : -1;
            }
            return candidate;
        }
    

    面试题 17.10. 主要元素

    题目:

    数组中占比超过一半的元素称之为主要元素。给你一个 整数 数组,找出其中的主要元素。若没有,返回 -1 。请设计时间复杂度为 O(N) 、空间复杂度为 O(1) 的解决方案。
    
    示例 1:
    
    输入:[1,2,5,9,5,9,5,5,5]
    输出:5
    示例 2:
    
    输入:[3,2]
    输出:-1
    示例 3:
    
    输入:[2,2,1,1,1,2,2]
    输出:2
    

    这道题跟上一道题的区别在于有可能没有主要元素,也就是数组中没有重复数字。

    解法思路:

    法一

    首先应该能想到的就是HashMap的解法,将数组放到map中,然后一旦map中的数组某个元素个数超过数组长度的1/2,返回,否则返回-1;

    代码:

      //使用hash表完成,一旦元素超过hash表的一半,则说明找到了
            HashMap<Integer, Integer> map = new HashMap<>();
            for(int num:nums){
                map.put(num, map.getOrDefault(num, 0)+1);
                if(map.get(num)>nums.length/2){
                    return num;
                }
            }
            return -1;
    

    法二

    跟一类似,首先将元素放到HashMap中,然后根据map的value降序排序成list,最后取出list中第一个元素的key值,如果第一个key值大于数组长度的2/1的话,直接返回,否则的话返回-1.

    代码:

      public int majorityElement(int[] nums) {
            HashMap<Integer, Integer> map = new HashMap<>();
            for (int num : nums) {
                map.put(num, map.getOrDefault(num, 0) + 1);
            }
            //根据map的value排序
            List<Map.Entry<Integer, Integer>> list = new ArrayList<Map.Entry<Integer, Integer>>(map.entrySet());
            list.sort(new Comparator<Map.Entry<Integer, Integer>>() {
                @Override
                public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
                    return o2.getValue().compareTo(o1.getValue());
                }
            });
    
            if (list.get(0).getValue() > nums.length / 2) {
                return list.get(0).getKey();
            }
    
            return -1;
        }
    

    法三

    也就是接续169多数元素之后的步骤:由于不一定存在主要元素,所以需要再遍历一遍数组,验证candidate是否是主要元素。

    看代码吧:

    package com.leetcode.everyday;
    public class MajorityElement_2 {
        public int majorityElement(int[] nums) {
            int count = 0;
            Integer candidate = null;
            for(int num:nums){
                if (count==0){
                    candidate=num;
                }
                if(num==candidate){
                    count++;
                }else{
                    count--;
                }
            }
            //遍历数组,查找candidate的值出现的次数是否大于nums的数量
            int ansCount = 0;
            for(int num:nums){
                if (num==candidate){
                    ansCount++;
                }
            }
            if(ansCount*2>nums.length){
                return candidate;
            }else {
                return -1;
            }
        }
    
        public static void main(String[] args) {
            int[] arr = {1,2,5,9,5,9,5,5,5};
            System.out.println(new MajorityElement_2().majorityElement(arr));
        }
    }
    
    

    还有小细节,count类型是包装类,是一种引用类型,所以可以赋值为null。


    总结

    1. 掌握Boyer-Moore 投票算法。

    2. 再熟悉map根据value排序的算法:

      		 //根据map的value排序
      List<Map.Entry<Integer, Integer>> list = new ArrayList<Map.Entry<Integer, Integer>>(map.entrySet());
      list.sort(new Comparator<Map.Entry<Integer, Integer>>() {
      @Override
          public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
                return o2.getValue().compareTo(o1.getValue());
              }
       });
      
    博客网站 https://yamon.top 个人网站 https://yamon.top/resume GitHub网站 https://github.com/yamonc 欢迎前来访问
  • 相关阅读:
    上传图片至fastdfs显示连接超时
    Linux上安装maven
    multipartFile.getOriginalFilename();不能获取原文件名称,也就是含有路径名
    /usr/bin/ld: cannot find -lfdfsclient
    linux开放22端口
    Ajax上传file出现的bad request问题
    easyui combobox实现下拉自动提示补全功能
    js格式化时间
    codeforces 780B
    codeforces 61 D 115 A
  • 原文地址:https://www.cnblogs.com/chenyameng/p/14991360.html
Copyright © 2011-2022 走看看