1. 题目描述
[229] 求众数‖
给定一个大小为 n 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。
进阶:尝试设计时间复杂度为 O(n)、空间复杂度为 O(1)的算法解决此问题。
示例 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
Related Topics 数组
2. 思路分析
这道题可以理解为 多数元素 的进阶,条件从 n/2 转变成了 n/3。
-
简单入手的思路,可以通过一样的排序,之后找到统计数大于 n/3 的数,然后返回。
-
参考 多数元素 的思路,采用摩尔投票法
但是,从 多数元素的题目我们可以得知,摩尔投票法的效率更加高,因此,也尝试使用摩尔投票法的方法来解答。解析题目可以知道,返回的集合,最多有两个数字,我们用两个变量来表示最后留下来的两个数字,再取两个变量来分别表示前面两个数字出现的次数
然后在遍历数组的过程中,如果出现不等于两个变量的值的情况,则对两个变量的统计数分别减去1。
最后的结果有可能存在两个数字的出现次数都不超过 n/3 ,因此,还需要对两个数字出现的次数来进行判断,再得出最后的结果
3. AC代码
public class No229 {
public List<Integer> majorityElement(int[] nums) {
// return method1(nums);
return method2(nums);
}
/**
* 排序后比较
* 执行耗时:3 ms,击败了37.38% 的Java用户
* 内存消耗:42.6 MB,击败了15.00% 的Java用户
*/
private List<Integer> method1(int[] nums) {
List<Integer> re = new ArrayList<>(nums.length / 3);
Arrays.sort(nums);
int flag = nums.length / 3;
int nowNum = nums[0];
int nowNumCount = 0;
for (int num : nums) {
if (num == nowNum) {
nowNumCount++;
} else {
if (nowNumCount > flag) {
re.add(nowNum);
}
nowNum = num;
nowNumCount = 1;
}
}
if (nowNumCount > flag) {
re.add(nowNum);
}
return re;
}
/**
* 摩尔投票法
*
* 执行耗时:2 ms,击败了97.06% 的Java用户
* 内存消耗:42.1 MB,击败了71.02% 的Java用户
* @param nums
* @return
*/
private List<Integer> method2(int[] nums) {
int flag = nums.length / 3;
// 返回的列表,最大只有2
List<Integer> re = new ArrayList<>(2);
// 初始化
int[] numArr = new int[]{ nums[0], nums[0] };
int[] numCountArr = new int[]{ 0, 0 };
// 如果非候选数组的数字,则统计数组的计数全都-1,统计数如果存在为0的话,就替换到数组的数字
for (int i = 0; i < nums.length; i++) {
if (nums[i] == numArr[0]) {
numCountArr[0]++;
} else if (nums[i] == numArr[1]) {
numCountArr[1]++;
} else if (numCountArr[0] == 0) {
numArr[0] = nums[i];
numCountArr[0] = 1;
} else if (numCountArr[1] == 0) {
numArr[1] = nums[i];
numCountArr[1] = 1;
} else {
--numCountArr[0];
--numCountArr[1];
}
}
// 归0重新计数统计
numCountArr[0] = 0;
numCountArr[1] = 0;
// 无法确定候选人的票都大于 n/3 需要遍历确认
for (int num : nums) {
if(num== numArr[0]) {
numCountArr[0]++;
} else if(num== numArr[1]) {
numCountArr[1]++;
}
}
if(numCountArr[0] > flag) re.add(numArr[0]);
if(numCountArr[1] > flag) re.add(numArr[1]);
return re;
}
}
4. 总结
学习要学会举一反三,我们从 【169-多数元素】中学到了摩尔投票法,在遇到类似的问题的时候,是否可以变通的去使用,更有效率的解答问题。
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情