题目链接: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.

这道题的要求是找到数组中的主要元素(指的是出现次数超过数组大小一半的元素),假设数组非空并且肯定存在主要元素。

可以暴力解决,就是统计每个数字出现的次数,返回最大值即可。时间复杂度O(n^2)。

  1. Hash表

建Hash表,统计每个数字出现的次数,返回最大的或者出现次数超过数组大小一半的。

时间复杂度:O(n)

空间复杂度:O(n)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution 
{
public:
    int majorityElement(vector<int> &num) 
    {
        unordered_map<int, int> cnt;
        for(int i = 0; i < num.size(); ++ i)
            ++ cnt[num[i]];
        
        for(auto it = cnt.begin(); it != cnt.end(); ++ it)
            if(it -> second > num.size() / 2)
                return it -> first;
        return 0;
    }
};
  1. Sort排序

先排序,然后返回数组中的⌊ n/2 ⌋位置的元素。

由于必有主要元素,因此⌊ n/2 ⌋位置的元素就是主要元素。

时间复杂度:O(nlogn)

空间复杂度:O(1)

1
2
3
4
5
6
7
8
class Solution {
public:
    int majorityElement(vector<int> &num)
    {
        sort(num.begin(), num.end());
        return num[num.size() / 2];
    }
};
  1. 分治

将数组拆分成左右2个子区间,分别统计每个区间的主要元素a和b。

  • 如果a等于b,那么a(或者b)就是全局主要元素;
  • 否则,分别统计a和b出现的次数,出现多的就是主要元素。

至于求子区间的主要元素,可以递归进行处理。

时间复杂度:O(nlogn)

空间复杂度:O(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public:
    int majorityElement(vector<int> &num)
    {
        return majorityElement(num, 0, num.size() - 1);
    }
private:
    int majorityElement(vector<int> &num, int l, int r)
    {
        if(l == r)
            return num[l];
        
        int m = (l + r) / 2;
        int a = majorityElement(num, l, m);
        int b = majorityElement(num, m + 1, r);
        
        if(a == b)
            return a;
        
        int cnt_a = 0, cnt_b = 0;
        for(int i = l; i <= r; ++ i)
        {
            cnt_a += num[i] == a ? 1 : 0;
            cnt_b += num[i] == b ? 1 : 0;
        }
        return cnt_a > cnt_b ? a : b;
    }
};
  1. Moore投票

用cur维护当前元素,cnt维护当前元素的数量。每次读取元素:

  • 如果cnt等于0,说明没有当前元素,那么cur赋值成刚读取的元素,同时cnt置1;
  • 否则,如果刚读取的元素与cur相同,cnt加1;如果不同,cnt减1。

这样,最后剩下的cnt就是数量多于数组大小一半的主要元素。

时间复杂度:O(n)

空间复杂度:O(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
    int majorityElement(vector<int> &num)
    {
        int cur = 0, cnt = 0;
        for(int i = 0; i < num.size(); ++ i)
        {
            if(cnt == 0)
            {
                cur = num[i];
                ++ cnt;
            }
            else
                cur == num[i] ? ++ cnt : -- cnt;
        }
        return cur;
    }
};
  1. 位操作

由于必有某一元素数量超过数组大小一半,因此该元素的每一位上的数字也是所有元素中对应位上最多的,因此只需统计每位上0和1出现的次数即可。

  • 如果某位上1出现次数大于0,那么结果该位为1;
  • 否则,结果该位为0。(不会出现相等情况)

时间复杂度:O(n)

空间复杂度:O(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
    int majorityElement(vector<int> &num)
    {
        int res = 0;
        for(int i = 0; i < 32; ++ i)
        {
            int cnt[2] = {0, 0};
            for(int j = 0; j < num.size(); ++ j)
                ++ cnt[(num[j] >> i) & 1];
            
            if(cnt[0] < cnt[1])
                res |= 1 << i;
        }
        return res;
    }
};