Day10_22

80 阅读1分钟

Day-10_22每日一题之求众数||

229. 求众数 II

难度中等449

给定一个大小为 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
  • -10^9 <= nums[i] <= 10^9

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

解题思路

刚拿到这个题的时候,直接想法就是用hashmap直接存,再读一遍找出所有出现次数超过n/3的元素添加到List集合中,输出即可

仔细想了一下其实根本不需要遍历两次,再添加的过程中直接判断出现次数,并加入set去重就行了,只不过这样需要再将set转换为list来输出结果,但目前思路只有这个了

代码

 class Solution {
     public List<Integer> majorityElement(int[] nums) {
         Set<Integer> set = new HashSet<>();
         Map<Integer,Integer> map = new HashMap<>();
         for(int num : nums) {
             int count = map.getOrDefault(num,0) + 1;
             if(count > nums.length/3 && !set.contains(num)) set.add(num);
             map.put(num,count);
         }
 ​
         List<Integer> ls = new ArrayList<>();
         Iterator<Integer> it = set.iterator();
         while(it.hasNext()) {
             ls.add(it.next());
         }
         return ls;
     }
 }
  • 时间复杂度:O(n);两次遍历
  • 空间复杂度:O(n):使用了额外的set,map,和list,长度均为线性O(n);

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

乍一看这道题是不是非常眼熟 > - < 这里顺带来复习一下摩尔投票

摩尔投票法

对于一个数如果其出现次数超过了数组长度的一半,那么其就是多数元素,那么我们假设这个数为x,其他的数为y,两两一抵消,最后剩余的肯定是多数元素x。落实到代码里,请看

169. 多数元素

难度简单1173

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

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

示例 1:

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

示例 2:

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

进阶:

  • 尝试设计时间复杂度为 O(n)、空间复杂度为 O(1) 的算法解决此问题。
 class Solution {
     public int majorityElement(int[] nums) {
         // 初始化数值为任意元素,count只统计出现次数
         int x = -1,count = 0;
         for(int num : nums) {
             if(count == 0)  {
                 x = num;
                 count++;
             }
             else if(num == x) count++;
             else count--;
         }
         return x;
     }
 }
  • 时间复杂度: O(n)
  • 空间复杂度: O(1)

回归本题,由于题目要求使用O(1)的空间,那么实际上联系上题,就可以想到摩尔投票法,只不过上一个题只要求找一个,而这道题通过分析我们可以发现,出现超过n/3的元素最多只有两个

这里我们通过设置四个变量,分别x1,x2,count1,count2分别来统计这两个元素

上代码

 class Solution {
     public List<Integer> majorityElement(int[] nums) {
         int n = nums.length;
         int x1 = 0,x2 = 0;
         int count1 = 0,count2 = 0;
 ​
         for(int num : nums) {
             // 前两个判断语句就是计数,与上一题类似,自不过这里要统计两个
             if(count1 != 0 && x1 == num) {
                 count1++;
             }else if(count2 != 0 && x2 == num) {
                 count2++;
             // 这里就是赋值操作,当两两抵消后就重新赋值
             }else if(count1 == 0 && ++ count1 >= 0) {
                 x1 = num;
             }else if(count2 == 0 && ++ count2 >= 0) {
                 x2 = num; 
             }
             // 这里就是进行抵消操作
             else count1--;count2--;
         }
         
         // 再次遍历原数组统计超过n/3的个数,因为不一定豆腐好条件,s
         count1 = 0; count2 = 0;
         for(int num : nums) {
             if(x1 == num) count1++;
             else if(x2 == num) count2++;
         }
         
         List<Integer> res = new ArrayList<>();
         if(count1 > n/3) res.add(x1);
         if(count2 > n/3) res.add(x2);
         
         return res;
     }
 }

\