LintCode majority numbe (主元素)
2015-12-26 13:46
393 查看
LintCode 主元素
主元素给定一个整型数组,找出主元素,它在数组中的出现次数严格大于数组元素个数的二分之一。
给出数组[1,1,1,1,2,2,2],返回 1
挑战
要求时间复杂度为O(n),空间复杂度为O(1) 。
solution:
对于这个问题,有很多解决的方法。
Method1. 最基本的解决方法
使用两个for循环计算出每个元素出现的次数, 如果该次数大于数组元素的二分之一就返回该元素, 及伪代码为:
//arr[] n = arr.length; //数组元素的个数 for i = arr[0] to arr[n-1] count = 0 for (j = arr[0] to arr[n-1] if (arr[i] == arr[j] and i != j) ++count; if count > size/2 return arr[i]
对于该方法,其时间复杂度为O(n2)O(n^{2}), 空间空间复杂度为O(1)O(1)。
Method2. 排序
很明显,题目中的意思是该元素一定存在。因此,可以对数组进行排序。那么arr[size/2]一定是该主元素。
/** * @param nums: a list of integers * @return: find a majority number */ public int majorityNumber(ArrayList<Integer> nums) { // write your code Collections.sort(nums); return nums.get(nums.size()/2); }
注意:该方法只有当主元素一定存在时才有效。
如果使用快速排序对该数组进行原址排序那么其时间复杂度为O(nlogn)O(nlogn), 空间复杂度为O(1)O(1)。
Method3. 使用hashmap
使用HashMap来计算,其中key用来存储元素,而value表示元素出现的次数。
public static int majorityNumber(ArrayList<Integer> nums) { Map<Integer, Integer> map = new HashMap<>(); for (int e : nums) { Integer count = map.get(e); count = (count == null ? 1 : count+1); if (count > nums.size()/2) return e; map.put(e, count); } return -1; }
很显然写这篇博客的原因,并不是简简单单的为了解决该问题。而是为了学习。在题目中有个挑战:要求时间复杂度为O(n),空间复杂度为O(1) 。因此,Google时发现了Moore’s Voting Algorithm,该算法可以在O(n)O(n)解决该问题。
因此,以下内容翻译自:GeeksforGeeks Majority Element
该博客中还提到了一种解决该问题的方法,使用二叉查找树。
Method4. 二叉查找树
其中二叉查找树的数据域如下:
struct tree { int element; int count; }BST;
对于每一个元素都保存了一个计数器,用来计数每个元素出现的次数。
因此,对于数组中的元素,一个一个的插入到二叉树中。如果该元素已经存在二叉树中则计数器加一。并且判断该计数器是否大于size/2,如果是则返回该元素,否则继续插入元素。
其中,该方法的最好情况是所有的主元素都在数组中开头的位置。例如:{1, 1, 1, 1, 1, 2, 3, 4}.
时间复杂:对于一般的二叉树为O(n2)O(n^{2})。 如果使用平衡二叉查找树则时间复杂度为O(nlogn)O(nlogn)。
Method5. Moore’s Voting Algorithm
该算法有两个步骤:
1. 获取数组中出现次数最多的元素。这个过程将会确保如果存在一个主元素(majority element), 就讲该元素返回。
2. 检查从上面步奏获取的元素是否是主元素。
(1). 找出候选元素 (finding a Candidate):
我们可以使用Moore’s Voting Algorithm来找出该元素,其时间复杂度为O(n)O(n)。该算法最基本的思想就是:如果e是一个主元素, 那么我们就可以抵消所有与e不相同的元素对。并且剩下的元素一定是e。
也可以如下理解:
每次都找出一对不同的元素,从数组中删掉,直到数组为空或只有一种元素。 不难证明,如果存在元素e出现频率超过半数,那么数组中最后剩下的就只有e。
Moore’s Voting Algorithm伪代码为:
findCandidate(a[], size) 1. Initialize index and count of majority element maj_index = 0, count = 1 2. Loop for i = 1 to size – 1 (a)If a[maj_index] == a[i] count++ (b)Else count--; (c)If count == 0 maj_index = i; count = 1 3. Return a[maj_index]
Moore’s Voting Algorithm遍历了每一个元素,并且对元素a[maj_index]a[maj\_index]维持了一个计数器countcount,如果下一个元素与该元素相同那么countcount加1,如果不相同那么countcount减1。如果countcount等于0,那么把当前元素的索引i i 赋值给maj_indexmaj\_index并且设置countcount为1。
Moore’s Voting Algorithm 算法选出了一个候选元素(candidate element)。那么接下来,我们就要去检查该元素是不是一个majority element。该过程很简单并且很容易在O(n)O(n)下做到。我们只需要去检查该元素出现的次数是否大于n/2.
例如:
A[] = 2, 2, 3, 5, 2, 2, 6
1). 初始化:
maj_index = 0, count = 1 –> candidate 2 ?
i = 1;
2 = a[maj_index] –> count = 2
i = 2;
3 != a[maj_index] –> count = 1
i = 3;
5 != a[maj_index] –> count = 0
因为,count= 0, 所以改变candidate为5 –> maj_index = 3, count = 1
i = 4;
2 != a[maj_index] —> count = 0 —> candidate 2, maj_index=4, count = 1
i = 5;
2 = a[maj_index] –> count = 2
i = 6;
6 != a[maj_index] –> count = 1
那么就有majority element = 2.
(2). 检查第一步所得到的元素是不是主元素majority element
printMajority (a[], size) 1. Find the candidate for majority 2. If candidate is majority. i.e., appears more than n/2 times. Print the candidate 3. Else Print "NONE"
注意:Moore’s Voting Algorithm 只有主元素一定存在时该算法才有效,否则该算法返回错误的结果。因此,第二步检查是有必要的!
Talk is cheap, show me the code !
// Moore’s Voting Algorithm private static int findCandidate(ArrayList<Integer> nums) { int maj_index = 0, count = 1; for (int i = 1; i < nums.size(); ++i) { if (nums.get(i).equals(nums.get(maj_index))) count++; else count--; if (count == 0) { maj_index = i; count = 1; } } return nums.get(maj_index); } private static boolean isMajority(int [] nums, int cand) { int count = 0; for (int e : nums) { if (e == cand) ++count; } return count > nums.length / 2 ; }
Moore Voting Alogrithm 可以更加泛化的求解数组中至少出现n/kn/k次的元素,详情请看Moore’s Voting Algorithm。
相关文章推荐
- java 构造方法
- Android动态轮播焦点图
- Android启动过程深入解析
- 【线性规划与网络流24题】孤岛营救问题 分层图
- Next Permutation
- GOROOT、GOPATH、GOBIN、project目录
- Fragment
- 四层和七层负载均衡的区别
- Android获取TextView控件高度(其它View类似,TextView有特殊之处)
- 最后关于Pipeline完整的图如下:
- 操作系统实验之作业调度算法
- python的out of memory问题
- nginx 配置详解
- Java 多线程(1)-Thread和Runnable
- codeforces 508D . Tanya and Password 欧拉通路
- HDU 1003:Max Sum【水】
- <php+mysql>PHP脚本对数据库的基本操作,查找,删除,循环输出
- VS project 根目录 配置OpenGL 相关库
- 微信分享失败之checkArgs fail, thumbData is invalid
- 【剑指offer】2.4.1查找和排序——面试题8:旋转数组的最小数字