一道讓人蛋疼的面試題

  昨日看到了兩道面試題,有兩道,第一道不少人都答出來了,第二道卻鮮有人回答。我本人最近在學習php,因此本文以php爲基礎帶來今天帶來第二道的分析。php

  附兩道面試題:面試

  1:大廳裏有100盞燈,每盞燈都編了號碼,分別爲1-100。每盞燈由一個開關來控制。(開關按一下,燈亮,再按一下燈滅。開關的編號與被控制的燈相同。)開始時,燈是全滅的。如今按照如下規則按動開關。
第一次,將全部的燈點亮。
第二次,將全部2的倍數的開關按一下。
第三次,將全部3的倍數的開關按一下。
以此類推。第N次,將全部N的倍數的開關按一下。
問第100次按完之後,大廳裏還有幾盞燈是亮的。


  2:有一根27釐米的細木杆,在第3釐米、7釐米、11釐米、17釐米、23釐米這五個位置上各有一隻螞蟻。木杆很細,不能同時經過一隻螞蟻。開始時,螞蟻的頭朝左仍是朝右是任意的,它們只會朝前走或調頭,但不會後退。當任意兩隻螞蟻碰頭時,兩隻螞蟻會同時調頭朝反方向走。假設螞蟻們每秒鐘能夠走一釐米的距離。編寫程序,求全部螞蟻都離開木杆的最小時間和最大時間。數組

 

      第一道比較簡單很少說了,第二道看着就讓人頭疼。函數

  簡單分析一下這道題。學習

  從題自己來看,貌似同時考慮五個螞蟻的位置着實讓人摸不着頭腦。所幸題的最後一句仍是頗有用的,全部螞蟻都離開木杆的最大時間和最小時間。將細杆做爲一個橫向的座標軸。螞蟻位置都已經給出。當最後離開的螞蟻的位置<=0或者>=27的時候,全部螞蟻離開木杆。(這貌似是廢話。)spa

  每秒1米,這樣的題設足夠讓人舒服。畢竟在此處螞蟻運動的時間數值上等於螞蟻運動的路程的數值。(若是考慮全部螞蟻離開木杆還繼續保持原有速度運動的話)。而且它們是同時運動。code

  螞蟻的運動方向只有兩個,向左或向右。考慮到座標軸的實際狀況,若是咱們假設向右移動爲1,那麼等價向左移動爲-1。在計算機的二元世界這一步考慮是很是重要的。blog

  好了,前面是鋪墊,無論您看懂看不懂,下面是更加劇點的內容。字符串

  求最大時間和最小時間,就像咱們在一堆數裏面找最大數和最小數同樣,這種事情應該不是很難。關鍵是找到最後作比較的時間。 時間和什麼有關係?從題設來看,只應該和初始每隻螞蟻的運動狀態有關。至於期間某個時刻某隻螞蟻的運動狀態咱們有必要糾結麼?不必。那樣只會將問題複雜化。get

  螞蟻初始狀態有幾種?2^5=32種。顯然這32種每種花費時間都要算,利用一個簡單的循環就能夠了。

  關注螞蟻運動狀態無非兩個變量:位置和方向。於是在此處我簡單引入兩個數組 $arr和$b 。前者用來描述某個點的當前位置,後者用來當前方向。 $b[i] 

 如前面所描述的,取值只應該是-1或者1。

 

  考慮到這裏,咱們就能夠捋順思路,給數組'$arr'和'$b'賦予一個初始值。利用時間'$i'作循環,每一秒每隻螞蟻移動後,當'$arr[$k]==$arr[$k-1]'時,改變相匹配的狀態值'$b[k]'的值。 當全部的'$arr'的'value'<=0或者>=27時,中止循環,返回'$i'。其中用了大量的循環遍歷。固然爲了簡便,當'$arr[$k]'再也不杆子上時,能夠利用unset()函數將其刪除。最後判斷'$arr'爲空就能夠結束循環。

 

  講完主體內容,咱們還必須處理一個小細節,如何生成描述螞蟻運動狀態的數組"$b"?

  總不能手動生成吧,5只螞蟻32種狀況,10只螞蟻1024種狀況手動生成着實蛋疼。但你明明又知道生成32個數組,不能不利用。於是咱們很容易想到將十進制數轉化爲長度爲5的二進制數。再將這個二進制數中的0替換爲-1。將替換後的字符串轉化爲數組。

  貼上相應代碼:

<?php
for($j=0;$j<32;$j++){

    $var=sprintf("%05b", $j);

    $var=str_replace('1', '1|', $var);
    $var=str_replace('0', '-1|', $var);

    $b=explode('|',$var);

    $res=getRes($b);


    if (isset($min)) {
        if ($res<$min) {
            $min=$res;

        }
    }else{
        $min=$res;
    }
    if (isset($max)) {
        if ($res>$max) {
            $max=$res;
        }
    }else{
        $max=$res;
    }
    print_r($b);
    echo "這次結果是".$res.'   $max='.$max.'  $min='.$min;
    echo "<hr/>";

}


echo "最大值是".$max."最小值是".$min;


//得到某種狀況下的時間
function getRes($b){
    $arr=array(3,7,11,17,23);
    for($i=1;$i<100;$i++){

        foreach ($arr as $k => $val) {
            $arr[$k]=$val+$b[$k];
            if ($arr[$k]==@$arr[$k-1]) {
                $b[$k]=-$b[$k];
                $b[$k-1]=-@$b[$k-1];
            }

            if (($arr[$k]>=27)||($arr[$k]<=0)) {
                unset($arr[$k]);
            }
        }


        if (empty($arr)) {
            return $i;
        }


    }

}

  這是按套路出牌的,循規蹈矩,一步一步走過來,但確實也十分辛苦。

------------------------------------- ---華麗的分隔線-------------------------------------------------------------------------------------------

 

   在我一本正經地胡說八道後,就沒有更加好的想法

  那就是相遇的時候,兩隻螞蟻開始掉頭。若是不掉頭直接走呢?和他們掉頭後有什麼差異?結果是沒有差異!每隻螞蟻開頭拿一個接力棒,碰頭後,兩人交換接力棒,雖然螞蟻掉頭了,但接力棒但是一直往初始方向走哦~因此解題前景變得無比明朗。知道某隻螞蟻的初始狀態,就知道他開始拿的接力棒最後走了多久!至於接力棒是否是親生的,那你管哩。反正最後一個接力棒離開杆子,最後一隻螞蟻也離開杆子。

  於是得到某種初始狀態下的時間還能夠這樣寫:

function getRes($b){
    $arr=array(3,7,11,17,23);
    for($i=1;;$i++){

        foreach ($arr as $k => $val) {
            $arr[$k]=$val+$b[$k];

            if (($arr[$k]>=27)||($arr[$k]<=0)) {
                unset($arr[$k]);
            }
        }

        if (empty($arr)) {
            return $i;
        }


    }


}

------------------------------------- ---華麗的分隔線-------------------------------------------------------------------------------------------   

  

  固然問題能夠更加簡化,連上面的代碼都用不到了。

  經過上面分析能夠看作每隻螞蟻直接走互不影響。到最後求最大值最小值的時候實際上能夠先算出每隻螞蟻到兩端的距離。造成五組數字。(3,24),(7,20),(11,16),(10,17),(4,23)在五組數每組數中較小值造成的5個數中最大的一個是最後結果的最小值。  五組數每組數中較大的5個數中最大的那個是結果的最大值。很容易看出來是11和24。爲何呢?典型的木桶效應啊。最後一隻螞蟻走出去了才能算完成整個事情。五隻螞蟻所有最短路徑出去,獲得結果纔多是最快的,五隻螞蟻所有最長路徑出去,耗時才能是最慢的。

  ps:應該不會有更快的想法了吧。

   最後感謝@randeng在本問題上的指點~

相關文章
相關標籤/搜索