小米筆試:“楊輝三角”&“排排坐吃果果”|掘金技術徵文

穎子發表於2017-09-19

或許每一個武大的學生,都會對小米有不一樣的情懷吧。
畢竟雷軍作為武大傑出校友已經名滿天下,創業經歷也足夠勵志傳奇,對學校的情懷也是特別吸粉的一點。
今年4月回武大頒發“雷軍獎學金”之後,微博那句“願你走出半生,歸來仍是少年”簡直戳中無數少女心,想進小米的情愫早已在心底根種。


所以9月18號小米的筆試我也是尤其用心了,晚上六點半早早坐在電腦前等著,也許我與學長的距離通過這倆小時就大幅縮排了呢。
這裡跟大家分享其中兩個完整的前端程式設計題:“楊輝三角”和“排排坐吃果果”(哈哈,這是我給取的名,原諒寫程式的小女生就這點樂子了,先賣個關子,到下面跟大家解釋)。

題一描述:

一個整數三角形,三角形的每一行都比上面一行多出一個數字(第1行有1個數字,第2行有2個數字,以此類推);每個數字,都等於它上方(如果有的話)與左上方兩個數字之和,如下圖所示:


現在給出一個數,請算出它最開始出現在第幾行?
輸入:一個正長整形數,保證為長整形的正數。
輸出:這個數最開始出現的行數。

拿到題第一感覺很親切,感謝小學數學老師每天放學後額外留給我的奧數題,誰也沒想到會在十幾年後再次遇見“楊輝三角”。事後在網上一搜,發現巨多用程式語言列印出來的“楊輝直角”,C、C++、C#、JAVA……看來大家都是如此的富於樂趣啊

迴歸正題,一開始想拿著數字去反推,這果斷是個錯誤。
還好思路馬上剎車轉彎,把這個直角三角形寫出來列印出來啊,
每列印一行我就判斷一次,判斷這一行裡有沒有給的這個數。

window.onload=function(){
    function countNum(x){       
        if(x==1){return 1}      //函式輸入1直接返回1
        var arr=[[1],[1,1]]        //定義陣列初始值
        for(var i=2;i<x+1;i++){ //從第三行開始建立資料
                arr[i]=[]            
                arr[i].push(1)        //每一行第一個預設為0    
                for(var j=1;j<i;j++){    //從每一行第二列開始遍歷
                    arr[i].push(arr[i-1][j-1]+arr[i-1][j])
                    //每個數字,都等於它上方(如果有的話)與左上方兩個數字之和
                }
                arr[i].push(1)        //每一行最後一個也是1
                if(arr[i].indexOf(x)>0){    //完成一行遍歷後,檢視這一行中有沒有需要的數
                    console.log(arr)
                    return i+1
                }        
        }
        }
        console.log(countNum(10))
    }複製程式碼

題一隻要把思路相對了其實不難,上面的解法也相對簡單,大家應該都能看明白。關於題二,個人覺得稍微難點,且看下方分解咯!

題二描述:

食堂有一張靠牆的長桌,規定每個人必須隔著吃飯,不允許挨著。現在長桌上已經有了一些各自獨處得人,來了一些新人,判斷他們能否找到位置?
輸入一個字串table,只含有0和1,1表示有人,0表示沒有人
輸入一個正整型的數n,表示新來就餐的人數
輸出一個布林值,能夠安排所有的人,返回false,否則返回true
例子:輸入1001,1
那麼顯然沒有位置給新來的一個人,返回false

情景轉移一下,是不是很像幼兒園裡小朋友們,排排坐等著老師發果果吃?怕小朋友們起爭執,所以小朋友需要間隔來坐。
原諒我看到這道題真的是腦補了一幅好有愛的畫面……

這個問題的關鍵無非也就是,“有人”=1,“沒人”=0,1跟1之間必須隔著0。
也許很多人剛看到題目會想著去找間隔,把0變成1,好吧,我也是這樣。
但是這樣馬上就自己也把自己繞暈了。其實我們不一定要去動這個字串,換個視野,把這道題看成計數的問題是不是SO EASY?

建模對於程式設計是如此的重要!
建模對於程式設計是如此的重要!
建模對於程式設計是如此的重要!

重要的事情說多少遍都不嫌多,演算法題尤其要注意建模思路,
找對思路很簡單,要是跑偏了就別提多痛苦,
如果此時的你也正在被一輪輪筆試轟炸,我相信你懂!

這道題我的思路是這樣的:
1、先把字串兩邊的0找出來,是2的倍數則可以坐一個人,比如001,可以坐一個人,0001還是隻能坐一個人,00001可以坐兩個人,中間的演算法和這個類似,但有所不同
2、再取中間1**1這樣的字串,遇到一個0則將其計數,當遇到下一個1終止計數
3、這時有一個規律,個數為1,2不能坐人0,3,4可以坐一個人,5,6可以坐兩個人。。。依次類推

function isOk(table,n){
        if(n<=0){return true; }            //輸入人數為0,直接返回true
        if(typeof table=='string'||table instanceof String){    //判斷是否是字串
            var start=0,end=0,newTable=[],
            arr=table.split(''),length=arr.length
            num=0;
            //start是第一個1的位置,end是最後一個1的位置,newTable是一個新
            //陣列,用來存放把兩邊0截掉後形如1***1這樣的字串
            //num用來臨時存放一組0的個數
            for(var i=0;i<length;i++){
                if(arr[i]=='1'){//找出字串裡的第一個“1”
                    start=i    //找到一個1即將索引賦值給start
                    n=n-parseInt(start/2)  //由於0的個數,n減掉部分值
                    break                   //找到一個1就停止迴圈
                }
            }
            for(var j=length-1;j>0;j--){
                if(arr[j]=='1'){
                    end=j
                    n=n-parseInt((length-1-end)/2)
                    break
                }
            }
            newTable=arr.slice(start,end+1)     //擷取掉兩邊的0後的陣列
            newTable.forEach(function(item){
                if(item=='0'){                  //對一組0進行計數
                    num++
                }else if(item=='1'){
                    n=n-parseInt((num-1)/2)     //找全一組後,n減掉部分值
                    num=0                       //並重置num,重新計數
                }
            })
            return n<=0?true:false
            //在迴圈外面判斷,n是否被減完了,為了降低某些情況下的遍歷次數
            //也可以在每次n減完後馬上判斷n是否小於0,是否需要中止整個操
            //作,這種在給定的n比較小的時候能大大降低遍歷次數
        }else{
            return true;
        }
    }複製程式碼

好辣,排排坐現在也做好了!

總歸來說呢,小米的校招知識廣度還是有的,除了前端專業知識,演算法、作業系統、資料結構、智商情商都有涉及,前面被BAT虐了之後,做完小米的題竟然會覺得學長的店還是些許溫柔的,說不定有戲哈哈。

關於上面兩道題,歡迎大家有好的思路跟我討論,其實我都不好意思說這兩套解法已經是我經過了幾個小時琢磨後的成果了。考試畢竟跟平時的心態會有變化,尤其是我一緊張腦子就不好使,有好的面經筆經還望各位不吝賜教辣,小女子在此謝過!
附掘金秋招徵文大賽連結

相關文章