本文已参与「新人创作礼」活动,一起开启掘金创作之路。
题目
算法解释
之前的解题报告里,我们已经使用了普通的一种解决方法,而进阶的解题方法要求O(n)的时间复杂度和O(1)的
空间复杂度,也就是说,必须线性方法就要解决问题,这时候我们也应该能发现,通用的解法已经行不通了,那么我
们要引入一个新算法——摩尔投票法
摩尔投票法,顾名思义,就是解决投票选举类似的问题,我们先构思一个场景,如果有n个人在进行选举,大家
投票来选举最终的候选人,得票超过n/2的人即可获胜(假设一定会存在这样一个),一般来说,简单思路就是统计
最后票数然后得结果就好了,那如果说选举人都不喜欢数学,不想数学,喜欢简单粗暴的方法,而每个人投票人实力
相同,1V1谁也不占上风,都能同归于尽,大家不同阵营的打一架,俩俩抵消出局,那最后留下来的一定就是多数的
阵营,这就是简单的摩尔投票法。
算法变换
而在这个题目当中,我们发现,情况又不一样了,这里不是求N/2,而是N/3,但其中的思想没有改变,那我们的
算法该如何进行一个变化使得摩尔投票法能重新适用呢?
其实我们可以想象一个临界条件,N/2时,什么情况下会出现选不出来的情况?均票,而均票的一个极端就是2
个人,一人N/2,那么其实N/3时的极端均票情况也差不多,3个人,每人都是N/3,N/2情况选不出是因为俩俩抵消了
,那N/3情况呢?没错,就是三三抵消了!但这时有人会说,如果投票情况是{1,1,1,2,2,1},三三抵消那还剩下1
和2,而2是不合要求的,这时候我们其实只要对这两个数字再遍历检验一下就OK了,而且不影响其O(N)的时间复杂
度,而空间复杂度上,我们需要的也就是新建几个变量,O(1)的空间复杂度,妥妥的!
代码
class Solution {
public List<Integer> majorityElement(int[] nums) {
List<Integer> ans = new ArrayList<>();
int num1 = 0,num2 = 0,times1 = 0,times2 = 0;//各数字与计数器
int length = nums.length;
for(int i = 0;i < length;i++)
{
if(nums[i] == num1) times1 ++;
else if(nums[i] == num2) times2 ++;
else if(times1 == 0) {
num1 = nums[i];
times1 ++;
}
else if(times2 == 0){
num2 = nums[i];
times2 ++;
}
else
{
times1 --;times2 --;
}
}
if(times1 > 0)//最后验证一下即可
{
times1 = 0;
for(int i = 0;i < length;i++)
if(nums[i] == num1) times1 ++;
if(times1 > length/3)
ans.add(num1);
}
if(times2 > 0)
{
times2 = 0;
for(int i = 0;i < length;i++)
if(nums[i] == num2) times2 ++;
if(times2 > length/3)
ans.add(num2);
}
return ans;
}
}