小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
求众数II
该题出自力扣的229题——求众数II(中等题),题解消化于官方题解
审题
原题:给定一个大小为 n 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。
-
给一个大小为n的数组,找出超过n/3次数的元素
-
特别的是要设计一个时间复杂度为O(n),空间复杂度为O(1)的算法解答
-
(√)方法一:统计次数,利用下标即可
- 定义一个HashMap,key为数组元素,value为出现的次数
- 第一个循环,遍历数组,分别插入hashMap,如果存在则value+1;反之value为1
- 第二个循环,遍历hashMap,判断每一个key的value是否大于数组长度的1/3
- 输出List
-
(√)方法二:利用摩尔投票算法
-
首先,摩尔投票算法是一个数组内,假设存在元素一定大于数组长度的1/2;那个这个元素一定只有1个
- 因为,假设元素X,数量为len(X);数组的长度为n;其他所有元素加起来 = n - len(X);但是前提是len(X)已经大于1/2的n了,所以最多只会有一个元素;
-
推演出来,超过1/3的元素,最多只会有两个;可以用三三抵消的方法,最终剩下的就是超过1/3的元素;
- 遍历数组,找出三三抵消后的元素
- 再次遍历,校验剩下的数是否超过数组的1/3
- add进List
- 输出List
-
编码实现
public List<Integer> majorityElement2(int[] nums) {
/*
摩尔投票法————当有一个数组,其中有一个数必然大于这个数组长度的1/2的时候,这个数一定只有一个
因为:假设长度为n,大于长度的数 = x;剩下的部分为 y,x的长度为n-len(x);而前提是x>n/2;所以剩下的部分加起来都不足一半,
也就只有一个数
推演:
有一个数>长度的1/3;那么最多只有两个数或者只有一个数
*/
int element1 = 0;
int element2 = 0;
int vote1 = 0;
int vote2 = 0;
for (int num:nums){
if (vote1>0 && num == element1){
vote1++;
}else if (vote2>0 && num == element2){
vote2++;
}else if (vote1 == 0){
element1 = num;
vote1++;
}else if (vote2 == 0){
element2 = num;
vote2++;
}else {
vote1--;
vote2--;
}
}
int cnt1 = 0;
int cnt2 = 0;
for (int num:nums){
if (vote1>0 && num == element1){
cnt1++;
}else if (vote2>0 && num == element2){
cnt2++;
}
}
List<Integer> list = new ArrayList<>();
if (vote1 > 0 && cnt1 > nums.length / 3){
list.add(element1);
}
if (vote2 > 0 && cnt2 > nums.length / 3){
list.add(element2);
}
return list;
}