169. 求众数 求超过 ⌊ n/2 ⌋
次的元素
简单
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋
的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
1 | 输入:[3,2,3] |
示例 2:
1 | 输入:[2,2,1,1,1,2,2] |
进阶:
- 尝试设计时间复杂度为 O(n)、空间复杂度为 O(1) 的算法解决此问题。
Moore投票法介绍
首先我们了解下什么是摩尔投票法:其基于一个事实: 当数组中存在某个数个数大于数组长度的1/2 时,我们可以使用使用摩尔投票法找出这个数。
算法:设置一个候选人和一个计数器 count
。遍历数组,每次遇到和候选人一样的值则 ++count
,否 则 --count
。当 count == 0
时替换候选人。最后剩下的就是我们所求的众数。
那么为什么能这样求呢?首先我们可以把数组中的数分为两类:众数和其他数。 算法中遇到和候选人不一样的值进行 --count
时其实可以看成一次互拼。而我们必须要保证这个互拼只有以下2种情况:
- 众数和其他数互拼,两者同时消耗1.
- 其他数和其他数互拼,其他数消耗2.
如果我们想要最后剩下的都是众数,那么按照对众数最不利的情况是所有的互拼都是情况1。而由于众数的个数大于 \(\lfloor n / 2 \rfloor\),所以最不利的情况最后留下来的也是众数。
而在算法中我们保证互拼只有以上2种情况的方法就是:我们遇到相同的候选人则 ++count
,这样可以避免众数和众数互拼(因为众数肯定是相等的,所以相同的时候 ++count
就避免了众数和众数互拼)
1 | int majorityElement(vector<int>& nums) { |
229. 求众数 II 求超过 ⌊ n/3 ⌋
次的元素
中等
给定一个大小为 n 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋
次的元素。
进阶:尝试设计时间复杂度为 O(n)、空间复杂度为 O(1)的算法解决此问题。
示例 1:
1 | 输入:[3,2,3] |
示例 2:
1 | 输入:nums = [1] |
示例 3:
1 | 输入:[1,1,1,3,3,2,2,2] |
提示:
1 <= nums.length <= 5 * 104
-109 <= nums[i] <= 109
Moore投票进阶版——求超过 ⌊ n/3 ⌋
次的元素
区别:
- 求超过
⌊ n/3 ⌋
次的元素最多有两个,所以我们可以改变思路寻找两个众数,将三个不同的元素放在一起对碰,具体方法如下:
有别于原版的Moore投票,因为至多可能有两个元素符合要求,所以需要两个元素的值及计数器;
比较时首先比较当前元素是否等于两个当前计数的元素,若相等,对应计数器 + 1;
若都不相等,分两种情况:
有值为0的计数器
将更新元素为当前元素,
++count
;两个计数器均不为0
两个计数器分别 - 1,三个不同元素一组消消乐。
最后计数检查留下来的元素出现次数是否符合要求,符合则压入数组。
1 | vector<int> majorityElement(vector<int>& nums) { |
Moore投票法总结
优势:
- \(O(n)\) 的时间复杂度 \(O(1)\) 的空间复杂度
限制条件:
- 限制众数出现的次数要在某个比例之上,且需要提前知道这个比例,若数组中众数出现次数小于这个比例,则不能正常求解。