给定一个大小为 n 的数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。
说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1)。
示例 1:
输入: [3,2,3]
输出: [3]
示例 2:
输入: [1,1,1,3,3,2,2,2]
输出: [1,2]
本题如果没有时间复杂度和空间复杂度的要求,那非常简单,用一个map即可,但是有了这个要求,就非常难了,我自己也是百思不得其解,想不到该如何去做,看了题解才明白有一种摩尔投票算法可以专门解决此类问题。
所谓的摩尔投票算法就是能找到一组数组中超过一半的数的一个算法。运用的是抵消删除的思想,从数组的开头进行遍历,初始化一个数字为第一个数字,当遇见相同数字,count就加一,如果没遇见就count减一,当如果count为0,遇见不同数字的时候,就将数字设定为该不同数字。遍历到最后返回的数字就是超过一半的数了。其实就是遇见不同的数字就抵消一次,那最后剩下的数字就一定是出现次数最多的,如果是有超过一半的数,那一定就是次数最多的,因此就是答案。
而本题就可以借鉴这个思想,我们初始化两个不同的数字进行遍历既可满足题目的要求,遍历中用摩尔投票算法的思想就可以解决本题了。
-
注意:本题选出来的两个数字是最多的两个数字,不一定都超过了n/3,如果数组中没有其他数字那么两个数字是相同的,也是需要关注的。
代码如下:
class Solution {
public List<Integer> majorityElement(int[] nums) {
if(nums.length == 0) return new ArrayList<Integer>();
int count1 = 0,count2 = 0;
int cand1 = nums[0];
int cand2 = nums[0];
for(int i = 0 ;i < nums.length ; i++){
if(nums[i] == cand1){
count1++;
continue;
}
if(nums[i] == cand2){
count2++;
continue;
}
if(count1 == 0){
cand1 = nums[i];
count1++;
continue;
}
if(count2 == 0){
cand2 = nums[i];
count2++;
continue;
}
count1--;
count2--;
}
count1 = 0;
count2 = 0;
for(int n : nums){
if( n == cand1) count1++;
if( n == cand2) count2++;
}
List<Integer> ans = new ArrayList<>();
if(count1 > nums.length/3) ans.add(cand1);
if(count2 > nums.length/3 && cand1 != cand2) ans.add(cand2);
return ans;
}
}
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/majority-element-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
网友评论