leetcode169题解

leetcode 169. Majority Element

题目

Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.

You may assume that the array is non-empty and the majority element always exist in the array.
题目要求找到一个数组中出现次数超过n/2的元素。如[1,1,2],majority element就是1。

解题思路

这道题很经典,解法也非常多。整理了一下至少有七种,如下图所示:
leetcode169题解_第1张图片
最暴力的方法就是双重循环,统计每个元素的出现频次,但这种显然时间复杂度太高。
如果可以使用STL,那么这道题可以通过hash table来解决。用unordered_map统计频次即可,见方法1。

在leetcode上看到了两个很惊艳的算法,在这儿也分享一下。
首先就是随机法,随机从数组里面取一个数字,然后验证这个数字出现次数是否超过了n/2。方法很好理解,最好情况下,时间复杂度为O(n)。在leetcode上的运行时间为19ms,是几种方法中较快的了。代码见方法2.

其次是Moore Voting Algorithm,这是美帝一个教授81年提出了一个时间复杂度O(n),无需额外空间的算法。这是他们网站上的演示。算法的基本思想是:每次都找出一对不同的元素,从数组中删掉,直到数组为空或只有一种元素。 不难证明,如果存在元素e出现频率超过半数,那么数组中最后剩下的就只有e。
实际算法的实现过程如下:

在算法执行过程中,我们使用常量空间实时记录一个候选元素c以及其出现次数f(c),c即为当前阶段出现次数超过半数的元素。

在遍历开始之前,该元素c为空,f(c)=0。

然后在遍历数组A时,如果f(c)为0,表示当前并没有候选元素,也就是说之前的遍历过程中并没有找到超过半数的元素。那么,如果超过半数的元素c存在,那么c在剩下的子数组中,出现次数也一定超过半数。因此我们可以将原始问题转化为它的子问题。此时c赋值为当前元素, 同时f(c)=1。

如果当前元素A[i] == c, 那么f(c) += 1。(没有找到不同元素,只需要把相同元素累计起来)

如果当前元素A[i] != c,那么f(c) -= 1。 (相当于删除1个c),不对A[i]做任何处理(相当于删除A[i])

如果遍历结束之后,f(c)不为0,那么元素c即为寻找的元素。上述算法的时间复杂度为O(n),而由于并不需要真的删除数组元素,我们也并不需要额外的空间来保存原始数组,空间复杂度为O(1)。

代码见方法三。

AC代码如下

方法一:

class Solution {
public:
int majorityElement(vector& nums) {
 unordered_map count;
 int n=nums.size();
 for(int i=0;in/2)
        return nums[i];
 }
}
};

方法二:

class Solution {
public:
int majorityElement(vector& nums) {
int n = nums.size();
srand(unsigned(time(NULL)));
while (true) {
int idx = rand() % n;
int candidate = nums[idx];
int counts = 0; 
for (int i = 0; i < n; i++)
if (nums[i] == candidate)
counts++; 
if (counts > n / 2) return candidate;
}
}
};

方法三:

class Solution {
public:
int majorityElement(vector& nums) {
int index=0;
int count=1;
for(int i=0;i

总结

在leetcode上为easy难度,但这道题算是一个很经典的问题。而且可以衍生为找出一个数组中出现频次超过1/k的元素。这次也是完整地了解了这道题的多种解法,在图中出现的其余几种在这篇文章中没有提到,有兴趣的可以自己试一试。

你可能感兴趣的:(leetcode题解)