【算法31】寻找数组的主元素(Majority Element)
题外话
最近有些网友来信问我博客怎么不更新了,是不是不刷题了,真是惭愧啊,题还是在刷的,不过刷题的频率没以前高了,看完《算法导论》后感觉网上很多讨论的题目其实在导论中都已经有非常好的算法以及数学证明,只是照搬的话好像意义也不是很大,希望找到些有代表性的题目在更新,另外希望能接着前面的《穷举递归和回溯算法终结篇》一系列如动态规划、贪心算法类的终结篇,在梳理自己知识结构的同时也能够帮助读者们更系统的学习算法思想。好了话不多说,进入正题。
问题描述
给定一个数组A[n], 定义数组的主元素 ( Majority Element) 为数组中出现次数超过 n/2 的元素。设计一个高效的算法来寻找数组的主元素。题目来源在这里 。
解法一
最容易想到的方法就是便利数组进行元素计数,然后返回元素个数大于 n/2 的元素,这种方法需要 O(n) 的时间复杂度 和 O(n) 空间复杂度,不算是一个好方法。
解法二
在解法一的基础上考虑消去 O(n) 的空间复杂度,如果元素出现次数超过 n/2,那么假设数组已经排序的话,那么中位数就是我们要找的数。进一步的我们除了中位数,我们不需要其他的数排好序。问题进一步转化为求数组的中位数,推广版本就是在O(n)的时间内寻找第 i 大的数,这在算法导论上有详细的论述,网上资料也很多。基本来说,就是利用快排的 partition 对数组进行划分,分为 [..., pivot, ...] 三个部分,假设划分后 pivot 是第 m 个元素,如果 m == i, 则pivot 即为第 i 大元素;反之对如果 pivot 的位置在大于 i (m > i),则对 left 部分进行递归寻找第 i 大元素;反之对 right 部分进行递归寻找第 (i - m) 大元素。代码如下, 然而这种算法在大数组的情况下回超时。
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <queue>
#include <stack>
#include <algorithm>
#include <functional>
#include <utility>
#include <cstdio>
#include <cstdlib>
using namespace std; /*
* Return a position k, such that all the elements in [left, k)
* are smaller than or equal to num[k] && all the elements in
* (k, right] are larger than num[k]
*
* Note that here is the randomize version of partition, every time
* we choose a random number as the pivot.
*/
int RandomPartition(vector<int> &num, int left, int right)
{
// random partition
int rnd = rand() % (right - left + ) + left;
swap(num[rnd], num[right]); // pivot
int x = num[right];
int i = left - ;
for (int j = left; j < right; ++j)
{
if (num[j] <= x)
{
swap(num[j], num[i + ]);
i += ;
}
}
swap(num[right], num[i+]);
return i + ;
} /*
* Return the i-th ordered element in num[left, right] but without
* sorting the array.
*/ int RandomSelect(vector<int> &num, int left, int right, int i)
{
if (right - left + < i || left > right) return -; // partition the num[], return the pivot position m
int m = RandomPartition(num, left, right); // k is the number of element in num[left, m]
int k = m - left + ; if (k == i)
{
return num[m];
}
else if (k > i)
{
// find the i-th ordered element in num[left, m-1]
return RandomSelect(num, left, m - , i);
}
else
{
// find the (i-k)-th ordered element in num[m+1, right]
return RandomSelect(num, m + , right, i - k);
}
} /*
* return the median of num[]
*/
int majorityElement(vector<int> &num)
{
int n = num.size();
int mid = n / ;
return RandomSelect(num, , n-, mid);
} int main()
{
int a[] = {, , };
int b[] = {, , , }; vector<int> v1(a, a + );
vector<int> v2(b, b + ); cout << majorityElement(v1) << endl;
cout << majorityElement(v2) << endl; return ;
}
解法三
这种方法的思想是把 majority element 看成是 1,而把其他的元素看成是 -1。算法首先取第一个元素 x 作为 majority element,并计 mark = 1;而后遍历所有的元素,如果元素和 x 相等, 则 mark ++;否则如果不等, 则 mark--, 如果 mark == 0, 则重置 mark = 1, 并且更新 x 为当前元素。 由于majority element 的数量大于一半,所以最后剩下的必然是majority element. AC code 如下.
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <queue>
#include <stack>
#include <algorithm>
#include <functional>
#include <utility>
#include <cstdio>
#include <cstdlib>
using namespace std; int majorityElement(vector<int>& num)
{
int n = num.size();
if (n < ) return -;
if (n == ) return num[]; int x = num[];
int mark = ;
for (int i = ; i < n; ++i)
{
if (mark == )
{
mark = ;
x = num[i];
}
else if (num[i] == x)
{
mark++;
}
else if (num[i] != x)
{
mark--;
}
}
return x;
} int main()
{
int a[] = {, , };
int b[] = {, , , }; vector<int> v1(a, a + );
vector<int> v2(b, b + ); cout << majorityElement(v1) << endl;
cout << majorityElement(v2) << endl; return ;
}
参考文献
[1] 《算法导论》第二版,第九章 《中位数和顺序统计学》.
[2] http://people.cis.ksu.edu/~subbu/Papers/Majority%20Element.pdf
【算法31】寻找数组的主元素(Majority Element)的更多相关文章
- [经典算法题]寻找数组中第K大的数的方法总结
		
[经典算法题]寻找数组中第K大的数的方法总结 责任编辑:admin 日期:2012-11-26 字体:[大 中 小] 打印复制链接我要评论 今天看算法分析是,看到一个这样的问题,就是在一堆数据 ...
 - Java实现 蓝桥杯 算法训练 寻找数组中最大值
		
算法训练 寻找数组中最大值 时间限制:1.0s 内存限制:512.0MB 提交此题 问题描述 对于给定整数数组a[],寻找其中最大值,并返回下标. 输入格式 整数数组a[],数组元素个数小于1等于10 ...
 - 减治算法之寻找第K小元素问题
		
一.问题描写叙述 给定一个整数数列,寻找其按递增排序后的第k个位置上的元素. 二.问题分析 借助类似快排思想实现pation函数.再利用递归思想寻找k位置. 三.算法代码 public static ...
 - 算法导论 寻找第i小元素 9.2
		
PS1:如果单纯为做出这道题那么这个代价是O(nlgn),通过排序就可以了. 这里讨论的是O(n)的算法.那么来分析一下这个算法是如何做到O(n)的,算了不分析了,这个推到看起来太麻烦了.其实我想知道 ...
 - 主元素问题 Majority Element
		
2018-09-23 13:25:40 主元素问题是一个非常经典的问题,一般来说,主元素问题指的是数组中元素个数大于一半的数字,显然这个问题可以通过遍历计数解决,时间复杂度为O(n),空间复杂度为O( ...
 - lintcode 中等题:Majority number II 主元素 II
		
题目 主元素II 给定一个整型数组,找到主元素,它在数组中的出现次数严格大于数组元素个数的三分之一. 样例 给出数组[1,2,1,2,1,3,3] 返回 1 注意 数组中只有唯一的主元素 挑战 要求时 ...
 - Ex 2_23 如果一个数组超过半数的元素都相同时,该数组被称为含有一个主元素..._第二次作业
		
将数组A划分为两个数组A1和A2 ,各含有A的一半元素或一半多一个.若A中含有主元素x,则A1和A2中至少有一个数组含有主元素x,对A1和A2递归地计算有无主元素,若A只含有一个元素,则A的主元素就是 ...
 - Leetcode算法【34在排序数组中查找元素】
		
在之前ARTS打卡中,我每次都把算法.英文文档.技巧都写在一个文章里,这样对我的帮助是挺大的,但是可能给读者来说,一下子有这么多的输入,还是需要长时间的消化. 那我现在改变下方式,将每一个模块细分化, ...
 - 寻找数组中第K频繁的元素
		
问题是:给你一个数组,求解出现次数第K多的元素.当然leetcode上的要求是算法复杂度不能大于O(N*logN). 首先这个问题我先是在leetcode上看到,当时想了两种做法,做到一半都觉得不是很 ...
 
随机推荐
- Excel日期处理
			
short format = cell.getCellStyle().getDataFormat(); //其值为22 输入值类型为2018/6/28 17:25:48 if (format!=22) ...
 - jQuery源码解读三选择器
			
直接上jQuery源码截取代码 // Map over jQuery in case of overwrite _jQuery = window.jQuery, // Map over the $ i ...
 - windows server  2008 远程桌面连接数修改--无限连接
			
1.开启远程桌面 我的电脑 | 属性 | 远程设置 | 远程 | 进允许运行使用网络级别身份验证的远程桌面的计算机连接(更安全)(N)
 - 【英宝通Unity4.0公开课学习 】(五)47讲到75讲
			
不知不觉今天都已经看了快30讲了,虽然很想快马加鞭地将后面的内容看完,但为了学习的质量,还是挺下来写一篇blog :) 这两天有些昏昏沉沉的,但感觉生活还安排得不错,原因找去找来觉得是没怎么开窗透气. ...
 - 用HttpClient发送HTTPS请求报SSLException: Certificate for <域名> doesn't match any of the subject alternative names问题的解决
			
最近用server酱-PushBear做消息自动推送,用apache HttpClient做https的get请求,但是代码上到服务器端就报javax.net.ssl.SSLException: Ce ...
 - 165. Compare Version Numbers比较版本号的大小
			
[抄题]: Compare two version numbers version1 and version2.If version1 > version2 return 1; if versi ...
 - 【转】Https内部机制基础知识
			
互联网权威机构 - CA 机构,又称为证书授权 (Certificate Authority) 机构,浏览器会内置这些"受信任的根证书颁发机构" (即 CA). 数字证书 提及 H ...
 - 一款APP的交互文档从撰写到交付
			
我第一份工作的设计总监是前百度设计师,34岁,一线设计12年:今年聊天说转了产品总监,如今39岁还活跃在行业中…… 我第二份工作的部门总监是前腾讯工程师,38岁,一线开发14年:2年前在Q群里跟我们说 ...
 - 连接redis
 - KbmMW 4.30.00 发布
			
今天早上,KbmMW发布了4.30.00 版,这个版本开始支持XE4 的WIN/WIN64/OSX. 暂时不支持ios开发,同时加强了通过JSON 的对象序列化.还有就是解决了我提交的几个有关 汉字处 ...