Boyer-Moore 投票算法及应用解析

Boyer-Moore 投票算法


前言

柚子今天在做算法题中发现了Boyer-Moore投票算法的解法,由此整理了相关内容,下面我们一起来看下吧。


提示:以下是本篇文章正文内容,下面案例可供参考

一、投票算法的基本思想

Boyer-Moore 投票算法的基本思想是:
(1)在每一轮投票过程中,从数组中删除两个不同的元素,直到投票过程无法继续,此时数组为空或者数组中剩下的元素都相等。
(2)如果数组为空,则数组中不存在主要元素;
(3)如果数组中剩下的元素都相等,则数组中剩下的元素可能为主要元素。(可能的原因是,如果是这样的一个数组[1,2,3],那么剩下的元素是3,但是3并不是数量超过一半的元素。)

二、投票算法的应用:求众数

1.思想

如果我们把众数记为 +1+1,把其他数记为 -1−1,将它们全部加起来,显然和大于 0,从结果本身我们可以看出众数比其他数多。

2.算法

Boyer-Moore 算法的本质和分治十分类似。我们首先给出 Boyer-Moore 算法的详细步骤:

我们维护一个候选众数 candidate 和它出现的次数 count。初始时 candidate 可以为任意值,count 为 0;
我们遍历数组 nums 中的所有元素,对于每个元素 x,在判断 x 之前,如果 count 的值为 0,我们先将 x 的值赋予 candidate,随后我们判断 x:
如果 x 与 candidate 相等,那么计数器 count 的值增加 1;
如果 x 与 candidate 不等,那么计数器 count 的值减少 1。
在遍历完成后,candidate 即为整个数组的众数。

3.举例

例如下面的这个数组:

[7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 7, 7, 7, 7]

在遍历到数组中的第一个元素以及每个在 | 之后的元素时,candidate 都会因为 count 的值变为 0 而发生改变。最后一次 candidate 的值从 5 变为 7,也就是这个数组中的众数。

4.辅助证明

(1)首先我们根据算法步骤中对 count 的定义,可以发现:在对整个数组进行遍历的过程中,count 的值一定非负。这是因为如果 count 的值为 0,那么在这一轮遍历的开始时刻,我们会将 x 的值赋予 candidate 并在接下来的一步中将 count 的值增加 1。因此 count 的值在遍历的过程中一直保持非负。
(2)那么 count 本身除了计数器之外,还有什么更深层次的意义呢?我们还是以数组作为例子:
[7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 7, 7, 7, 7]
首先写下它在每一步遍历时 candidate 和 count 的值:

nums:      [7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 7, 7, 7, 7]
candidate:  7  7  7  7  7  7   5  5   5  5  5  5   7  7  7  7
count:      1  2  1  2  1  0   1  0   1  2  1  0   1  2  3  4

(3)我们再定义一个变量 value,它和真正的众数 maj 绑定。在每一步遍历时,如果当前的数 x 和 maj 相等,那么 value 的值加 1,否则减 1。value 的实际意义即为:到当前的这一步遍历为止,众数出现的次数比非众数多出了多少次。我们将 value 的值也写在下方:

nums:      [7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 7, 7, 7, 7]
value:      1  2  1  2  1  0  -1  0  -1 -2 -1  0   1  2  3  4

有没有发现什么?我们将 count 和 value 放在一起:

nums:      [7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 7, 7, 7, 7]
count:      1  2  1  2  1  0   1  0   1  2  1  0   1  2  3  4
value:      1  2  1  2  1  0  -1  0  -1 -2 -1  0   1  2  3  4

发现在每一步遍历中,count 和 value 要么相等,要么互为相反数!并且在候选众数 candidate 就是 maj 时,它们相等,candidate 是其它的数时,它们互为相反数!
(4)为什么会有这么奇妙的性质呢?这并不难证明:我们将候选众数 candidate 保持不变的连续的遍历称为「一段」。

在同一段中,count 的值是根据 candidate == x 的判断进行加减的。那么如果 candidate 恰好为 maj,那么在这一段中,count 和 value 的变化是同步的;
如果 candidate 不为 maj,那么在这一段中 count 和 value 的变化是相反的。因此就有了这样一个奇妙的性质。

三、总结

(1)这样以来,由于:我们证明了 count 的值一直为非负,在最后一步遍历结束后也是如此;
(2)由于 value 的值与真正的众数 maj 绑定,并且它表示「众数出现的次数比非众数多出了多少次」,那么在最后一步遍历结束后,value 的值为正数;
(3)在最后一步遍历结束后,count 非负,value 为正数,所以它们不可能互为相反数,只可能相等,即 count == value。因此在最后「一段」中,count 的 value 的变化是同步的,也就是说,candidate 中存储的候选众数就是真正的众数 maj。
(4)众数的算法解析见下文点击前往"算法解析"

参考链接:https://leetcode.cn/problems/majority-element/solution/duo-shu-yuan-su-by-leetcode-solution/


╭◜◝ ͡ ◜◝╮
( ˃̶͈◡˂ ̶͈ )感觉有用的话,欢迎点赞评论呀!
╰◟◞ ͜ ◟◞╯

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柚子猫屿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值