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.

Example 1:

Input: [3,2,3]
Output: 3

Example 2:

Input: [2,2,1,1,1,2,2]
Output: 2

 


 

非常简洁的题目, 找到出现次数最多的数字。

但是我没想到的是,官方竟然给出了6种各不相同的解法,献上我的膝盖~还是我太年轻了。

有不同的思路当然不能错过,说不定哪一天在这道题上增加一些条件之后,那种解法就是最优解了呢。

 

1.暴力求解

逐个对数组中每个元素计算个数,直接上代码可能更清晰一点:

for (int elem : nums) {
    int nowCount = 0;
    for (int nElem : nums) {
        if (elem == nElem) {
            ++nowCount;
        }
    }

    if (nowCount > numLen / 2) {
        return elem;
    }
}

虽然这种做法可以AC,但是算法复杂度极高。

 

2.hash映射(暴力解法的优化)

我们可以看到,在暴力解法中,对于重复的数字进行了多次计数,最简单的优化策略就是使用HashMap记录数字对应的出现次数,这样一次遍历就可以完成。实现的代码也不难理解:

for (int i = 0; i < numLen; ++i) {
    if (intCount.containsKey(nums[i])) {
        intCount.put(nums[i], intCount.get(nums[i]) + 1);
    } else {
        intCount.put(nums[i], 1);
    }
}

遍历完成之后,再遍历一遍HashMap找到数字最大的即可。但是提交后的代码表现不是很好,因为HashMap的一些内部操作也会浪费大量的时间。但是理论的时间复杂度只在O(N)。

 

3.排序法

排序这个方向我是思考过的,但是想到可以使用hash映射在O(N)的时间复杂度内解决,就没有继续思考下去,意想不到的是,排序这个方向的思路竟然这么简洁。首先我们可以知道的是数组中出现次数最多的元素,其出现次数必然比 N / 2 要大,我们是不是可以这么认为,排序之后的数组,在nums[nums.length / 2] 的位置上的元素必然是出现次数最多的元素。如下图所示:

无论是数组是奇数长度,还是偶数长度,在 nums[nums.length / 2] 处都是我们要的结果(注意现在的所说的除法都是按照整数除法来计算)。

代码简洁到了可以直接在这里放完整代码了:

class Solution {
    public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length / 2];
    }
}

提交后的结果达到了一个非常理想的时间,但是理论上的时间复杂度是O(N\log N),要比方法二的速度慢,但是实际结果却相反,并且Java的sort函数使用的是dual-pivot quick sort针对硬件层面也有了一定的优化,再加上HashMap操作也需要时间,更加大了两者的差距,反倒最后 \log N 倍的差距倒是不明显了。

 

4.随机查找法

 

5.分治法

 

6.博伊尔-摩尔投票算法

boyer-moore算法主要的用途就是在线性的时间和空间内,找到元素序列中包含最多的元素。

在本题的应用中,定义一个候选人变量candidate(用来记录扫描至当前位置时,可能的出现次数最多的元素),一个计数变量count,初始化都为0,然后开始循环;每次循环时检查count是否为0,记录当前元素为candidate,并检查当前元素与candidate是否相同,若相同则count + 1,若不同则count - 1。具体循环体如下:

for (int elem : nums) {
    if (count == 0) {
        candidate = elem;
    }

    count += elem == candidate ? 1 : -1;
}

整个过程与投票的过程非常相似,个数最多的元素就是最后的candidate值,这样的应用是有前提的,那就是保证有一个元素出现的次数大于 N / 2。

算法的理论时间复杂度为O(N),空间复杂度为常数,是这道题的最佳选择。

 


 

Boyer-Moore投票算法:

class Solution {
    public int majorityElement(int[] nums) {
        int count = 0;
        int candidate = 0;

        for (int elem : nums) {
            if (count == 0) {
                candidate = elem;
            }

            count += elem == candidate ? 1 : -1;
        }

        return candidate;
    }
}

 


如有错误,欢迎指摘。也欢迎通过左上角的“向TA提问”按钮问我问题,我将竭力解答你的疑惑。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值