到了大三下学期,身边的小伙伴都不约而同地开始找实习了,其中面试当然是不可缺少的重头戏啦。 最近在面百度的时候,面试官的一道关于随机数的题很有意思,不算难,但却在那么一瞬间触动了我,所以打算抽点时间把它记录下来。(关于它怎么触动我了,最后我会有说明 :P)

面试题的描述

大意是这样的:

写一个方法,把给定数组内的元素打乱返回,尽量高效实现。

首先,我想到的就是PHP自带的一个shuffle函数,就是专门干这个事儿的,随机打乱数组,而且是引用传值的。

当我说出可以使用shuffle函数时,面试官打断了我,说不能使用PHP自带的函数,让自己尝试着实现这个功能。当时很郁闷,明明有高度优化好的方法摆在那却不让用,唉…

然后,就发动脑袋想吧,想到既然在数组中不管是取值、打印还是赋值都是拿数组的下标操作的,所以我可以往数组下标这方面想,假如我可以打乱下标那不就解决了打乱数组了吗,于是就有了下面比较笨的代码,现在再回头看当时头脑发晕的解决方案,真是无语:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?php
$arrData = array('aaa', 'bbb', 'ccc', 'ddd', 'eee');
$keys = array_keys($arrData);
shuffle($keys);
$kLen = count($keys);
$arrRes = array();
foreach($keys as $v){
    array_push($arrRes, $arrData[$v]);
}
var_dump($arrRes);

尽管功能是实现了,但是其中还是使用了shuffle方法,这显然是不合格的。那种紧张情况下,我能想到的就这个思路了,汗~~

最后,没辙了,我就大胆问了下面试官能不能给一些提示,那个面试官真的很nice,然后就给出了提示:

说我往数组下标方面思考是正确的,既然要求要高效就意味着在同一个数组中完成操作,可以尝试着使用交换来完成。

对于一道面试题来说,面试官能提示这么多就已经很好了,然后我就顺着这个思路想下去,如果每次随机获取一个下标,然后把该下标对应的value与数组最后一个value交换,最后数组长度减一,接着重复执行上述步骤就可以了。

下面还是用图来说明下吧,毕竟一图胜千言嘛~~

假设随机拿到该数组的一个key为1,然后让key为1的元素与最后一个元素(key为4)交换

2015-06-12_223756

第一次交换后,数组长度减一,然后只需要对(数组长度-1)的元素执行相同操作即可。代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?php
$arrData = array('aaa', 'bbb', 'ccc', 'ddd', 'eee');
$arrLen = count($arrData)-1;
while($arrLen >= 0){
    $k = mt_rand(0, $arrLen);
    $tmp = $arrData[$arrLen];
    $arrData[$arrLen] = $arrData[$k];
    $arrData[$k] = $tmp;
    $arrLen--;
}
var_dump($arrData);

这样很好地就解决了这个问题。

总结

其实写这篇博客的目的并不是要记录这道面试题多么多么难,细想想的话怎么都不算难,对吧?其实,写这篇博客的原由是这样的,当我们在面试的时候,不可能都一帆风顺的,多少都会遇到几个棘手的面试题,你想想面试官的心态,肯定要考倒你的啊,当我们没有思路的时候,不要立刻就说不会或者其他放弃作答的话(想想这给面试官传递的信息对自己有多不利!),可以尝试着向面试官要一些解答提示,一般面试官都很好的,都会给出一些思路,然后你就顺着这个思路想下去,最后也许就柳暗花明了,又能给面试官很好的印象,何乐而不为呢?面试官往往并不是一定要得到正确答案,他们真正在乎的也许是你的思考方式。就像我,刚开始可能也没什么很好的解决办法,但是顺着他的思路一步步就那么把正确方法给做出来了。所以,下次再遇到难题,不妨向面试官要一些提示,记住啊~~

ps:呼应开头,触动我的理由想必大家都已清楚了吧。

(end)