OJ -- 169. Majority Element

问题描述:在一个数组里面找出出现次数最多的一个数,(出现次数最多在本题里面被定义成为:出现次数多于N / 2 次)

1.分析:
读完题目之后,会有几种解题方法浮现出来:
(1)直接使用数组的index来解决这个问题:

input : nums(arr of int)
let arr be a new arr:
    for num in nums:
        arr[num]++
    return max_element_in_arr

这种方法很容易想到,但是不切实际,因为数组里面的数字不可能全部都是正数,而且不知道最大值是多少,如果最大值为INT_MAX,不可能在栈上或者堆上开这么大的数组来使用。

(2)使用红黑树数据结构:

input : nums(arr of int)
let map be a new map:
    for num in nums:
        map[nums]++;
    return key_has_max_value_in_map

使用key-value数据结构可以很好地帮助我们解决这个问题,并且可以得到不错的时间复杂度(O(N)),但是使用了额外的空间,空间复杂度为O(N)。
对于这个题目,我们使用下面这个方法可以把空间复杂度下降到O(1):
我们先随机选取一个数组里面的元素:统计这个元素出现的次数,如果出现次数大于 N / 2,那么这个元素就是答案。:

input : nums(arr of int)
count = 0;
while 1:
    count = 0;
    let current be a random element in arr:
        for num in arr:
            if num == current:
                count++
        if count > N / 2
            return current

这样我们就能够把空间复杂度下降到O(1),并且平均时间复杂度也是O(N)。
具体的C++代码:

int majorityElement(vector<int>& nums) {
        int size = nums.size();
        int count = 0;
        while (1) {
            count = 0;
            int index = rand() % size;
            int target = nums[index];
            for (int i = 0; i < size; ++i) {
                if (target == nums[i]) {
                    count++;
                }
            }
            if (count > size / 2) {
                return target;
            }
        }
    }

(3)主元个数减掉不是主元的个数的值必然大于0:

int majorityElement(vector<int>& nums) {
        int major = nums[0];
        int count = 1;
        int size = nums.size();
        for (int i = 1; i < size; ++i) {
            major == nums[i] ? count++ : count--;
            if (count == 0) {
                major = nums[i];
                count = 1;
            }
        }
        return major;
    }

2.几个问题:
(1)为什么需要随机:
因为主元的个数大于 N / 2,在最坏情况下:前面的 N / 2个元素都不是主元,那么时间复杂度会上升到O(N^2)。
(2)为什么不直接用Map数据结构:
可以使用Map,并且很稳定(对于任何的输入都可以得到O(N)的时间复杂度),最后这种方法有点看脸,时间会有波动。最后一种方法只是在空间上面进行优化,使用随机来“随机保证”时间复杂度不变。

猜你喜欢

转载自blog.csdn.net/nia305/article/details/79804127