[每日算法] leetcode第169题Majority Element 和 第229题Majority Element II

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

题目大意

该题题意较为简洁,给定一串数字,求众数(这里的众数比较特别,数量 >= n/2),题目保证一定有该众数。

解题思路

该题的归类为easy,因为我们可以以比较暴力的求解,用一个map存储,每个数字都执行map[num]++,最后判断哪一个map[num] >= n/2即可求出对应众数。

但这样实现的算法的时间复杂度是O(n),但是需要的空间复杂度为O(n/2),那有没有空间复杂度为O(1)的算法呢,答案是有的,使用摩尔投票法。

摩尔投票法的基本思想很简单,在每一轮投票过程中,从数组中找出一对不同的元素,将其从数组中删除。这样不断的删除直到无法再进行投票,如果数组为空,则没有任何元素出现的次数超过该数组长度的一半。如果只存在一种元素,那么这个元素则可能为目标元素。

那么有没有可能出现最后有两种或两种以上元素呢?根据定义,这是不可能的,因为如果出现这种情况,则代表我们可以继续一轮投票。因此,最终只能是剩下零个或一个元素。

在算法执行过程中,我们使用常量空间实时记录一个候选元素c以及其出现次数f©,c即为当前阶段出现次数超过半数的元素。根据这样的定义,我们也可以将摩尔投票法看作是一种动态规划算法。

程序开始之前,元素c为空,f©=0。遍历数组A:

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

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

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

如果遍历结束之后,f©不为0,则找到可能元素。
再次遍历一遍数组,记录c真正出现的次数,从而验证c是否真的出现了超过半数。上述算法的时间复杂度为O(n),而由于并不需要真的删除数组元素,我们也并不需要额外的空间来保存原始数组,空间复杂度为O(1)。

C++实现代码

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int count = 0, majority;
        for (int num: nums) {
            if (count == 0) {
                majority = num;
                count++;
            } else {
                if (majority == num)
                    count++;
                else
                    count--;
            }
        }
        return majority;
    }
};

229. Majority Element II

原题目描述

Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times.

Note: The algorithm should run in linear time and in O(1) space.

Example 1:

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

Example 2:

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

题目大意

该题是上面那道题的扩展版本,难度为medium,需要我们求出前二众数(数量 >= n/3),题目不确定是否有,且有几个(<= 2)众数。

解题思路

同样的,我们可以选择使用map进行暴力求解,但是如此实现的空间复杂度就无法实现O(1)了,那么有没有什么办法使得空间复杂度为O(1)呢,答案是肯定有的,接着使用摩尔投票法。
参考上一题,我们使用两个变量记录前二众数,最终再对这两个数的出现次数进行判断即可,还是比较容易实现的。

C++实现代码

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        vector<int> res;
        int m = 0, n = 0, cm = 0, cn = 0;
        for (auto &a : nums) {
            if (a == m) ++cm;
            else if (a ==n) ++cn;
            else if (cm == 0) m = a, cm = 1;
            else if (cn == 0) n = a, cn = 1;
            else --cm, --cn;
        }
        cm = cn = 0;
        for (auto &a : nums) {
            if (a == m) ++cm;
            else if (a == n) ++cn;
        }
        if (cm > nums.size() / 3) res.push_back(m);
        if (cn > nums.size() / 3) res.push_back(n);
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值