[摩尔投票]一个求众数的方法

题目描述:

        给定一个大小为 的整数数组,找出其中所有出现超过  n/2  次的元素。

        示例1:

输入:[1,2,5,9,5,9,5,5,5]

输出:5

        示例2:

输入:[2,2,1,1,1,2,2]

输出:2

哈希表:

        首先我们想到的解法肯定是,获取每个元素数量,然后得到符合要求的元素的

var majorityElement = function(nums) {
    const cnt = new Map();

    for (let i = 0; i < nums.length; i++) {
        if (cnt.has(nums[i])) {
            cnt.set(nums[i], cnt.get(nums[i]) + 1);
        } else {
            cnt.set(nums[i], 1);
        }
    }
    const ans = [];
    for (const x of cnt.keys()) {
        if (cnt.get(x) > nums.length / 2) {
            ans.push(x);
        }
    }

    return ans;
};

  •         时间复杂度: O(n)
  •         空间复杂度: O(n)

摩尔投票: 

        摩尔投票法的核心思想就是对拼消耗。我们先假设这个有 n 个元素的数组里面,元素 a 的个数大于 \frac{n}{2} 的。那么我们能得到如下结论:

        1. 这样的元素肯定只有一个。

        2. 数组中同时少两个不相同的元素,则元素 a 的个数还是在剩下的 n-2 个元素中,数量大于 \frac{n-2}{2}

        所以我们的算法就是,依次遍历数组,记录当前元素,和当前元素出现的次数,如果,当前元素和之前的一样则,次数 +1,如果和之前的不一样,则之前元素的次数 -1,当前元素不计。这样可以获取这个可能存在的元素。然后再统计元素的数量。

var majorityElement = function(nums) {
    let element = 0;
    let vote = 0;

    for (const num of nums) {
        if (vote > 0 && num === element) { //如果该元素和之前元素相同,则计数加1
            vote++;
        } else if (vote === 0) { 
            element = num;
            vote1++;
        } else { //如果元素不相同,则相互抵消1次
            vote--;
        }
    }

    let cnt = 0;
    for (const num of nums) {
        if (vote > 0 && num === element1) {
            cnt++;
        }
    }
    // 检测元素出现的次数是否满足要求
    const ans = [];
    if (vote1 > 0 && cnt > nums.length / 2) {
        ans.push(element1);
    }
    return ans;
};
  •         时间复杂度: O(n)
  •         空间复杂度: O(1)

扩展题目:

        如果要找出,数量大于  n/3  的元素呢?

        

var majorityElement = function(nums) {
    let element1 = 0;
    let element2 = 0;
    let vote1 = 0;
    let vote2 = 0;

    for (const num of nums) {
        if (vote1 > 0 && num === element1) { //如果该元素为第一个元素,则计数加1
            vote1++;
        } else if (vote2 > 0 && num === element2) { //如果该元素为第二个元素,则计数加1
            vote2++;
        } else if (vote1 === 0) { // 选择第一个元素
            element1 = num;
            vote1++;
        } else if (vote2 === 0) { // 选择第二个元素
            element2 = num;
            vote2++;
        } else { //如果三个元素均不相同,则相互抵消1次
            vote1--;
            vote2--;
        }
    }

    let cnt1 = 0;
    let cnt2 = 0;
    for (const num of nums) {
        if (vote1 > 0 && num === element1) {
            cnt1++;
        }
        if (vote2 > 0 && num === element2) {
            cnt2++;
        }
    }
    // 检测元素出现的次数是否满足要求
    const ans = [];
    if (vote1 > 0 && cnt1 > nums.length / 3) {
        ans.push(element1);
    }
    if (vote2 > 0 && cnt2 > nums.length / 3) {
        ans.push(element2);
    }

    return ans;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值