[数据结构与算法]15 两行代码就可以搞定求众数,但还有更巧的
这个周末刷了几道算法题,把其中一个比较不错的分享给你~
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [3,2,3]
输出: 3
示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2
哦,原来是求众数,注意一下哈,这里的众数是指"在数组中出现次数大于 ⌊ n/2 ⌋ 的元素",不要问我为什么要你们注意一下这个条件,因为我钻牛角尖了!
拿到这个题目,我的第一反应就是,那我给这个数组排个序然后取中间的值不就得了?
所以代码就只有两行:
Arrays.sort(nums);
return nums[nums.length >> 1];
写完程序运行,一点儿毛病都没有,简简单单两行代码就搞定,那一刻我觉得我就是个天才!
后来梦醒了,冷静分析了一下,我去这样的代码简单是简单,但是时间复杂度是 O(nlogn) ,空间复杂度是 O(logn)
所以有没有更好的解决方案呢?能让它的时间复杂度和空间复杂度都降下来
必须得有哇!要不然我写这篇文章是为了啥
这种比较好的解决方案就是摩尔投票法
这个方法理解起来有点儿绕,我先来讲讲,这一块儿看懂了,咱们再往下走
先回到现实生活中,投票的时候咱们是怎么投的呢?大家每个人都选一个人,然后开始拆开纸团瞅瞅选的是谁,刚开始默认大家都是 0 票,然后纸条上投的是谁,这个人就多一票,最后看谁的票数比较多.
回到咱们这个题目,既然是众数,而且出现的次数大于 ⌊ n/2 ⌋ ,那我们可以假设一个数就是要求的众数,同时设置这个数字出现的次数为 0 ,然后和接下来的数字进行比较,如果一样呢,咱们把这个数字出现的次数加上 1 ,如果不一样,就让次数减 1 ,当这个值减到 0 时,说明刚开始假设的数字不是众数,那就换当前的这个数字,继续循环
这样最后这个数字出现的次数一定是大于等于 0 的,要不然就不符合 出现的次数大于 ⌊ n/2 ⌋
这个题意了
最后,将真正的众数返回即可
具体代码可见下面:
int count = 0 ;
Integer candidate = null;
for(int num : nums){
if (count == 0){
candidate = num;
}
count += ( num == candidate ) ? 1 : -1 ;
}
return candidate;
分析一下,这样实现的时间复杂度是 O(n) ,空间复杂度是 O(1)
和刚开始使用的方法相比,好了许多
你有没有更巧妙的方法实现,欢迎评论区和我交流哇
最后,感谢您的阅读~