笔试面试题目:阿里选班长

周末了,抽点时间练习算法,顺便保持对代码的感觉,免得生疏。毕竟,拳不离手,曲不离口。

今天,我们来看阿里巴巴公司的一道面试算法题目,初看起来挺简单的,其实不然。题目如下:

已知数组中有一个数字出现的次数,超过数组长度的一半,要求找出这个数字。

有的人看到题目后就开始做,也能得到正确结果,但无法通过面试,这是为什么呢?且往下看。

图片

一.暴力排序

排序是最容易想到的一种方法。由于目标元素的次数超过数组长度的一半,所以排序后直接取中间元素就行。

阿里巴巴会出这么简单的题目吗?有点搞笑!我们知道,基于比较的排序,时间复杂度能达到O(NlogN), 但这不是最好的方法,无法通过面试。

二.计数统计

既然题目的意思是求出这个次数超过一半的元素,那就对次数进行计数吧,直接搞个hashmap就行了。此时,时间复杂度是O(N), 但空间复杂度也是O(N),无法通过面试。

而且要注意到,使用计数法的时候,漏用了题目中的信息:超过数组长度的一半。显然,这是不合理的。这就跟你高考数学一样,你发现有个条件居然没用到,而你把题目做出来了,那是很值得怀疑的。

三.摩尔投票

接下来,我们来介绍一种很巧妙的思路,即摩尔投票法,时间复杂度是O(N), 空间复杂度是O(1),能满足面试要求。思路是怎样的呢?

我们来看一种现实中的投票场景:

班级要开始选班长

要求半数以上通过

选出来的就是班长

我们先来看一种简单的情况:假如只有2个人A和B竞争班长这一职位。那么,在大家投票后,我们从投票箱中取数后,可以这样统计:

  • 先抽一张票,如果是A,则记录当前胜利者为A,票数:1

  • 再抽一张票,如果是A,则记录当前胜利者为A,票数:2

  • 再抽一张票,如果是B,则抵消,记录当前胜利者为A,票数:1

  • 再抽一张票,如果是B,则抵消,记录无当前胜利者

  • 再抽一张票,如果是A,则记录当前胜利者为A,票数:1

  • ...

如此循环,直到所有票统计完毕,最后有票的一方,就是胜利者,就是大家选出来的班长。

图片

如上只是两方进行PK, 那么,当候选人为多人时,也可以使用类似的思路,这里的前提条件就是:一定存在多余半数票的候选人。

当多方进行PK时,占据着半数以上票数的班长,可以任性地抵消任何人的票,而且其他人之间的相互抵消也不会撼动班长的位置。

有的朋友看到这里,可能觉得有点绕,那么,我们一起来看看程序,并打印关键步骤,有兴趣的朋友可以对照程序和结果理解下。

阿里巴巴主要是用Java编程, 但也有C++岗位,如下是对应的C++程序代码:

#include <iostream>using namespace std;
int solution(int a[], int n) {      int count = 0, value = a[0];  for(int i = 0; i < n; i++)  {    printf("log, i=%d, count=%d, value=%d\n", i, count, value);    if(count == 0)    {      value = a[i];    }
    if(a[i] == value)    {      count++;    }    else    {      count--;    }   }
  return value;}

int main(){   int a[]={6,2,5,3,4,2,2,2,2,5};   int n = sizeof(a) / sizeof(a[0]);   cout << solution(a, n) << endl;   return 0;}

结果如下(经检验无误):​​​​​​​

log, i=0, count=0, value=6log, i=1, count=1, value=6log, i=2, count=0, value=6log, i=3, count=1, value=5log, i=4, count=0, value=5log, i=5, count=1, value=4log, i=6, count=0, value=4log, i=7, count=1, value=2log, i=8, count=2, value=2log, i=9, count=3, value=22

图片

好的,先说这么多,希望大家在刷题过程中,获得启发,举一反三,融会贯通,有所进步,拿到更多更好的offer, 薪资翻倍。

外界有点喧嚣和浮躁,然而我们可以稍微宁静一下,安心学习和积累,学习本身就是一件很纯粹快乐的事情,谁说不是呢?

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值