1、剑指 Offer 39. 数组中出现次数超过一半的数字[1]
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
摩尔投票算法是基于这个事实:每次从序列里选择两个不相同的数字删除掉(抵消),最后剩下一个数字或几个相同的数字,就是出现次数大于总数一半的那个。
目标:不断删除2个不同数字,直到无法删除。
对实现过程的理解:假设我们有2个隐形数组, array, result分别表示当前无法删除的元素和删除之后剩下的元素。
例:输入:{1,2,1,3,1,1,2,1,5}
遍历数组
1)从第一个元素1开始,由于目前array为空,无其它元素可以和1一起删除,所以暂时无法删除,加入array,array:{1}, result由于未删除任何元素,仍是{1,2,1,3,1,1,2,1,5}。
2)对第二个元素2,可以和之前扫描到的1一起删除,array:{ }, result: {1,3,1,1,2,1,5}。
3)4)对与后面2个元素{1, 3}的处理过程同 1)2),此时array:{ }, result: {1,1,2,1,5}。
5)处理同1),此时array:{ 1 }, result: {1,1,2,1,5}。
6)对第六个元素1,虽然此时array非空,但值和1相等,无法抵消,此时array:{ 1,1}, result: {1,1,2,1,5}。
7)对第七个元素2,可以和之前扫描到的1一起删除,此时array:{ 1}, result: {1,1,5}。
8)对第八个元素1,虽然此时array非空,但值和1相等,无法抵消,此时array:{ 1,1}, result: {1,1,5}。
9)对第九个元素5,可以和之前扫描到的1一起删除,此时array:{1}, result: {1}。
这个过程就是删除(抵消)了(1,2),(1,3),(1,5)剩下了一个1。
对array数组观察可以发现,array只能同时存储一种数值,因此可以采用 两个遍历majority, count分别代表array数组元素的数值,和数组长度。过程如下:
设当前扫描的元素为x,若count=0,即array为空,不存在可抵消数字,则将当前数字加入array,即majority=x;
若majority=x, 当前数字与前一个相同,无法抵消,加入array, count++;
若majority!=x, 当前数字与前一个不同,抵消, count--;
代码(c++)
int majorityElement(vector& nums) {
//摩尔投票法
int majority = 0, count = 0; //majority记录array里的元素,count记录array长度
for (auto x: nums)
{
if (count == 0)
majority = x;
if (majority == x)
count++;
else
count--;
}
return majority;
}
Leetcode229.求众数
给定一个大小为 n 的数组,找出其中所有出现超过 ⌊ n/3 ⌋
次的元素。
说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1)。
前面一题的升级版,且不保证一定存在众数。
和前面思路一致,但是array数组最多存在2个不同元素,因为出现超过 ⌊ n/3 ⌋
次的元素最多2个。
用cand1, cand2表示2个候选元素值,cnt1, cnt2表示元素数量。
vector majorityElement(vector& nums) {
int cand1 = 0, cand2 = 0, cnt1 = 0, cnt2 = 0;
for (auto x: nums)
{
if (cnt1 == 0 && cand2 != x)
cand1 = x;
if (cand1 == x)
cnt1++;
else if (cand2 == x)
cnt2++;
else if (cnt1 == 0){
cand1 = x;
cnt1++;
}
else if (cnt2 == 0){
cand2 = x;
cnt2++;
}
else { // x!=cand1 && x!=cand2
cnt1--;
cnt2--;
}
}
// 统计cand1, cand2出现次数,若> ⌊ n/3 ⌋,则加入结果
cnt1 = cnt2 = 0;
for (auto x: nums)
{
if (x == cand1)
cnt1++;
else if (x == cand2)
cnt2++;
}
vector res;
if (cnt1>nums.size()/3)
res.push_back(cand1);
if (cnt2>nums.size()/3)
res.push_back(cand2);
return res;
}
题目
[1] https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/
[2] https://leetcode-cn.com/problems/majority-element-ii/
参考
[3]https://www.zhihu.com/question/49973163