求众数 II 摩尔投票法

229. 求众数 II

难度 中等

给定一个大小为 n 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。

示例 1:

输入:[3,2,3]
输出:[3]

示例 2:

输入:nums = [1]
输出:[1]

示例 3:

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

提示:

  • 1 <= nums.length <= 5 * 104
  • -109 <= nums[i] <= 109

**进阶:**尝试设计时间复杂度为 O(n)、空间复杂度为 O(1)的算法解决此问题。

题解1 : hash 时间复杂度为 O(n) 空间复杂度为 O(n) hash空间

class Solution {
 public List<Integer> majorityElement(int[] nums) {
      //法 1 hashmap存放数字对应的次数
     List<Integer> res = new ArrayList<Integer>();
     Map<Integer,Integer> map = new HashMap<Integer,Integer>();
     for(int i : nums){
         if(map.containsKey(i)){
             map.put(i,map.get(i)+1);
         }else{
             map.put(i,1);
         } 
     }
     map.forEach((key,value) -> {
         if(value>nums.length/3){
             res.add(key);
         }
     });
     return res;

}

题解2 : 排序 计数 时间复杂度nlogn 空间复杂度O1

		//法2 排序 进行计数
     List<Integer> res = new ArrayList<Integer>();
     Arrays.sort(nums);
     int x=1; //记录出现的次数
     for(int i=1;i<nums.length;i++){
         if(nums[i]==nums[i-1]){
             x++;
         }else{
             if(x>nums.length/3)
             res.add(nums[i-1]);
             x=1;
         }
     }
     if(x>nums.length/3){
         res.add(nums[nums.length-1]);
     }
     return res;

题解三 : 摩尔投票法

基本思路 这个题要找大于length/3个数的数 , 所以最多只能有两个 , 所以我们就创建两个候选人变量element1element2变量 用来存放 票数最多的两个人 以及分别对应的票数vote1vote2

一开始进去 票数都为0(发现票数为0了就换人) , 所以候选人1就是第一个元素 , 并且它的票数加一 , 第二个候选人就是第二个不同的元素 , 票数+1 ,继续遍历的过程中 遇到与候选人一样的元素时并且票数大于0时,它的票数加一 最后遍历出来的一定是俩个票数最多的

完了开始计票 重新遍历 找出各自的总数然后再判断是否大于了三分之一总数

class Solution {
 public List<Integer> majorityElement(int[] nums) {
     int element1 = 0;
     int element2 = 0;
     int vote1 = 0;
     int vote2 = 0;

     for (int num : nums) {
         if (vote1 > 0 && num == element1) { //如果该元素为第一个元素,则计数加1
             vote1++;
         } else if (vote2 > 0 && num == element2) { //如果该元素为第二个元素,则计数加1
             vote2++;
         } else if (vote1 == 0) { // 选择第一个元素
             element1 = num;
             vote1++;
         } else if (vote2 == 0) { // 选择第二个元素
             element2 = num;
             vote2++;
         } else { //如果三个元素均不相同,则相互抵消1次
             vote1--;
             vote2--;
         }
     }

     //找出人了  开始计票
     int cnt1 = 0;
     int cnt2 = 0;
     for (int num : nums) {
         if (vote1 > 0 && num == element1) {
             cnt1++;
         }
         if (vote2 > 0 && num == element2) {
             cnt2++;
         }
     }
     // 检测元素出现的次数是否满足要求
     List<Integer> ans = new ArrayList<>();
     if (vote1 > 0 && cnt1 > nums.length / 3) {
         ans.add(element1);
     }
     if (vote2 > 0 && cnt2 > nums.length / 3) {
         ans.add(element2);
     }

     return ans;
 }
}

上面的是两个候选人的情况
下面的是一个候选人的情况

剑指offer 52.数组中出现次数超过一半的数字

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

假设数组非空,并且一定存在满足条件的数字。

思考题

  • 假设要求只能使用 O(n)的时间和额外 O(1)的空间,该怎么做呢?
样例
输入:[1,2,1,1,3]

输出:1

题解 : 票数严格大于一半时,只能有一个候选人

创建一个count用来记录票数

创建一个val用来存放符合条件的候选人

遍历的时候如果count等于0 就更新当前的候选人 票数加一

​ count不等于0时 , 再进行判断当前的值是否等于val 等于就count++ 否则就count–

class Solution {
    public int moreThanHalfNum_Solution(int[] nums) {
        //遍历一次 不能使用额外的空间
        //摩尔投票法
        int val =  0; //用于存放候选人
        int count = 0; //记录当前的票数
        for(int i = 0 ; i<nums.length;i++){
            if(count==0){
                val = nums[i];
                count++;
            }else{
                if(nums[i]==val)
                count++;
                else
                count--;
            }
        }
        return val;
        
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值