Leetcode (4) 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,次数>⌊ n/2 ⌋)。并且题目另加了说明,其数组非空,且该元素一定存在,因此我们就不需要在获得元素之后再判断一遍元素的出现次数是否>⌊ n/2 ⌋了。

解决代码

这里先给出本题的解决代码,下一部分再给出题目的思路(楼主是急性子也想先写代码再进行系统分析呢~~)。

方法一(统计每个元素出现个数),49 ms 中等水平的速度~~:

class Solution {
public:
    int majorityElement(vector<int> &num) {
        map<int,int> countMap;
        for (vector<int>::iterator it = num.begin(); it != num.end(); ++it)
        {
            if (countMap.find(*it) == countMap.end())
                countMap[*it] = 1;
            else
                countMap[*it]++;
        }

        int half = num.size() / 2;
        int element;
        bool findElement = false;
        for (map<int,int>::iterator it = countMap.begin(); it != countMap.end(); ++it)
        {
            if (it->second > half)
            {
                element = it->first;
                findElement = true;
                break;
            }
        }

        if (findElement)
            return element;
        else
            return -1;
    }
};

方法二(Moore voting algorithm),29 ms 比上一个算法快多了,思路也比较巧妙,详见下面的解释~~

class Solution {
public:
    int majorityElement(vector<int> &num) {
        if (num.size() < 1)
            return -1;

        int last = num[0];
        int count = 1;
        for (vector<int>::iterator it = num.begin()+1; it != num.end(); ++it)
        {
            if (last == *it)
                count++;
            else
            {
                count--;
                if (count == 0)
                {
                    last = *it;
                    count = 1;
                }
            }

        }

        return last;
    }
};

题目解法

这道题目LeetCode共给了7种解法,这里做一下说明,若嫌弃博主口齿不清者,请直接参看下面原文~~。

最简单的方法就是统计每个元素的出现次数,若次数大于⌊ n/2 ⌋则为我们所求的“众数”了,即“暴力求解(Brute force solution)”,这种方法最简单直接,当然时间复杂度最大,为 O(n2) ,所以这里不推荐这种方法。

第二种方法是使用一个哈希表去存储每一个元素,直接统计每个元素的出现个数,然后返回出现个数大于⌊ n/2 ⌋的元素即可。该方法的时间复杂度和空间复杂度都是 O(n) 。该方法有一个好处,就是在遍历hash_map得到Majority Element的时候还便可以顺道判断这个元素是否存在(不过本题不需要这个判断~)。楼主的第一方法大概就是这种思路的,使用了一个map去保存元素及其出现个数的。

第三种方法是基于排序的方法。输出排序后数组的中间( n/2 th)元素。然而比较排序的最优时间复杂度为 O(nlogn) ,该方法的时间复杂度也为 O(nlogn)

第四种方法为随机算法,个人认为这是一个很神奇的算法,因为在最坏的情况下你永远都得不到所求的元素。该方法的思路非常简单,即随机获取一个元素,并判断该元素是不是Majority Element,若是则返回该元素,若不是则再进行随机选取。这个方法主要是基于Majority Element的个数大于 ⌊ n/2 ⌋ ,因此每次都有大于1/2的概率获取到所求的元素。

第五种方法基于分治(Divide and conquer)的思想。类似于所有分治算法,对原数组先分为两部分,分别查找两个子数组的Majority Element,得到A和B两个元素,若A == B则说明该元素就是Majority Element,否则对A和B分别进行判断是否为Majority Element。时间复杂度为 T(n)=T(n/2)+2n=O(nlogn)

第六种方法为Moore voting algorithm。看着像一个人名命名的算法,这个算法非常巧妙的解决了求解Majority Element的问题。主要思想为:从头开始遍历数组,将第一个元素设置为当前元素,设置一个计数器count=0,若下一个元素与当前元素相等则将count+1,否则count-1,若count为0,则将目前遍历的元素设置为当前元素,继续遍历。遍历结束后保留的当前元素即为众数。上面的第二个代码便是基于该思想的。

第七种方法为基于位运算的方法。主要思想是统计int的32位上每一位的众数,每一位的众数即组成了Majority Element的每一位。

  • Runtime: O(n2) — Brute force solution: Check each element if it is the majority element.
  • Runtime: O(n) , Space: O(n) — Hash table: Maintain a hash table of the counts of each element, then find the most common one.
  • Runtime: O(nlogn) — Sorting: As we know more than half of the array are elements of the same value, we can sort the array and all majority elements will be grouped into one contiguous chunk. Therefore, the middle (n/2th) element must also be the majority element.
  • Average runtime: O(n) , Worst case runtime: Infinity — Randomization: Randomly pick an element and check if it is the majority element. If it is not, do the random pick again until you find the majority element. As the probability to pick the majority element is greater than 1/2, the expected number of attempts is < 2.
  • Runtime: O(nlogn) — Divide and conquer: Divide the array into two halves, then find the majority element A in the first half and the majority element B in the second half. The global majority element must either be A or B. If A == B, then it automatically becomes the global majority element. If not, then both A and B are the candidates for the majority element, and it is suffice to check the count of occurrences for at most two candidates. The runtime complexity, T(n)=T(n/2)+2n=O(nlogn) .
  • Runtime: O(n) — Moore voting algorithm: We maintain a current candidate and a counter initialized to 0. As we iterate the array, we look at the current element x:
    • If the counter is 0, we set the current candidate to x and the counter to 1.
    • If the counter is not 0, we increment or decrement the counter based on whether x is the current candidate.
    • After one pass, the current candidate is the majority element.
    • Runtime complexity = O(n) .
  • Runtime: O(n) — Bit manipulation: We would need 32 iterations, each calculating the number of 1’s for the ith bit of all n numbers. Since a majority must exist, therefore, either count of 1’s > count of 0’s or vice versa (but can never be equal). The majority number’s ith bit must be the one bit that has the greater count.

你可能感兴趣的:(LeetCode,C++,算法)