每周一题(1)摩尔投票

写在整个系列前的废话

这个系列主要是记录最近刷力扣时遇到的一些有趣的算法,笔者本人现大三准备保研,一方面是帮助自己记忆,另一方面也分享给基础较弱准备校招社招的小伙伴,助力大家一同成长。本系列博客将以例题为切入点,就解题思路分析算法的适用环境,并给出样例代码(通常是C,因为笔者主修硬件,编程这方面实际能力较弱,只会C、C++、java和python),如有问题欢迎在评论区进行讨论。

例题题目

8年纪3班今天组织了第13轮团员选拔,由于班主任阎老师把关严格,这次还是只入选一个人。小明主动报名了检票员,投票完成后,负责传投票箱的小芳说有一个人得到的票已经超过了一半,但是她记不得是谁了。小明于是决定找一个方法,以最快的速度完成点票。请你帮小明设计一个算法,快速的找出入选者。已知选拔采取一人一票的形式,得票最高且数量过半者入选。

解题思路

记入选者为 A A A,其选票数量为 N A N_A NA;其余人为 A ˉ \bar{A} Aˉ,数量为 N A ˉ N_{\bar{A}} NAˉ。假设发生随机抵消,任意两张不相同的的选票相互抵消,则会出现如下两种情况:

  1. A A A A ˉ \bar{A} Aˉ相互抵消,记数量为 n 1 n_1 n1
  2. A ˉ \bar{A} Aˉ之间相互抵消,记数量为 n 2 n_2 n2

则必然有:
n 1 ≤ N A ˉ n_1\leq N_{\bar{A}} n1NAˉ
由题已知:
N A ˉ < N A N_{\bar{A}}<N_{A} NAˉ<NA
则随机抵消发生后, A A A持有的选票数为:
N A − n 1 ≥ N A − N A ˉ > 0 N_{A}-n_1\geq N_{A}-N_{\bar{A}}>0 NAn1NANAˉ>0
即随机抵消后, A A A手中仍会持有选票,而 A ˉ \bar{A} Aˉ则不会持有选票。

在此基础上,我们写一个随机抵消过程:两个变量,分别用于记录待抵消的人员的编号与其现持有的选票数。遍历数组,投票对象与待抵消对象相同,则又发现一张选票,现持有选票书+1;投票对象与抵消对象不同,若待抵消选票数大于0,则发生抵消,带抵消选票-1,若带抵消选票数等于0,则更改抵消对象,抵消对象=投票对象,带抵消选票数=1。遍历一遍后,抵消对象即为入选者。

使用条件

  1. 每人投一票
  2. 入选条件是获得超半数的选票
  3. 入选者存在

资源占用

内存占用: O ( 1 ) O(1) O(1)
时间占用: O ( n ) O(n) O(n)

代码实现

以上题目使用C语言函数实现,其中 ∗ L i s t *List List为投票人数组, i i i表示 i i i号投票人, L i s t [ i ] List[i] List[i]为i号投票人的投票对象, L i s t L e n ListLen ListLen为输入数组的长度,返回 t a r g e t target target即为最终入选人员编号。

int MooreVoting(int *List,int ListLen)
{
    int target = List[0];
    int targetNum = 1;
    //初始票数为0,则假设第一个投票对象为抵消对象,录入第一张选票后,其持有选票数为1
    for(int i=1;i<ListLen;i++)
    //从第二张选票开始遍历
    {
        if(List[i]==target)
        {
            targetNum++;
        }
        //如果对象相同,累加待抵消票数
        else
        {
            if(targetNum!=0)
            {
                targetNum--;
            }
            //剩余选票数大于0,则扣除待抵消票数
            else
            {
                target = List[i];
                targetNum = 1;
            }
            //剩余选票数为0,更换抵消对象
        }
    }
    return target;
}

本期的废话

有没有消光大佬啊,最近换了个游戏本,刚入手,根本不会玩。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值