JAVA面试题——摩尔投票法

        在求解众数时,我们常见的方法是哈希统计,时间、空间复杂度是O(n)。有没有优化空间的算法呢?答案是肯定的——摩尔投票法。

        在LCR 158. 库存管理 II - 力扣(LeetCode)中,求取元素重复次数大于数组长度一半的元素。常规的哈希表方法不再赘述,这里只谈一下摩尔投票法。

        摩尔投票法是基于这样的原理:当一个数的重复次数超过数组长度的一半,每次删除两个不相同的数,最终剩下的即为答案。

        定义众数x为第一个元素,遍历数组时等于x则投票数+1,反之则-1。若投票数==0,说明在遍历过的元素中众数的个数等于其余元素,而由于众数在这里被定义成大于数组长度一半的元素,因此剩下没有遍历过的元素中,众数个数一定大于其他元素的。遍历结束,x即为可能答案。由于x的个数可能不到数组长度半(也就是不存在题目定义的“众数”),还需要计算个数。这里使用常数级别的空间复杂度O(1)。

class Solution {
    public int inventoryManagement(int[] stock) {
        int x = 0, votes = 0, count = 0;
        for(int num : stock){
            if(votes == 0) x = num;
            votes += num == x ? 1 : -1;
        }
        
        for(int num : stock)// 验证 x 是否为众数
            if(num == x) count++;
        return count > stock.length / 2 ? x : 0; // 当无众数时返回 0
    }
}

        对于类似问题,如,求大于数组长度/3的元素229. 多数元素 II - 力扣(LeetCode),可以参考leetcode官方题解,偷个懒:

class Solution {
    public List<Integer> majorityElement(int[] nums) {
        int element1 = 0;
        int element2 = 0;
        int vote1 = 0;
        int vote2 = 0;

        for (int num : 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--;
            }
        }

        int cnt1 = 0;
        int cnt2 = 0;
        for (int num : nums) {
            if (vote1 > 0 && num == element1) {
                cnt1++;
            }
            if (vote2 > 0 && num == element2) {
                cnt2++;
            }
        }
        // 检测元素出现的次数是否满足要求
        List<Integer> ans = new ArrayList<>();
        if (vote1 > 0 && cnt1 > nums.length / 3) {
            ans.add(element1);
        }
        if (vote2 > 0 && cnt2 > nums.length / 3) {
            ans.add(element2);
        }

        return ans;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值