最近遇見兩個算法題,當時沒有想到比較好的辦法,第二天在公交上思考了一下,感覺像是比較不錯的解題方法,今天記錄一下。公交車是一個不錯的思考場所!
一、有一個數組,長度為n,其中有若干個0,且不知道這些0所在的數組下標。要求:在不能開辟另外數組的情況下,用最少的空間復雜度和時間復雜度把所有的0排到最后去,且原來的非零數前后順序不變。
我一開始的思路是記錄0的個數x,遍歷數組,找0便把后面的所有數往前挪一位,然后把數組最后一個元素賦值為0,x+1。接著再找,找到第二個0,繼續把后面的往前挪,然后把數組倒數第二個元素賦值為0,x+1。繼續此方法,直至遍歷到下標為 n - x - 2 的元素。想想效率太差了,最差的情況下要交換 ?(n - 1 +1) / 2 * (n - 1)次,時間復雜度為O(n2),空間復雜度為O(0)拙劣的思考。
后面我思考到了一個比較不錯的方法:遍歷數組,找到0之后記錄該元素的下標index,繼續往后遍歷,找到第一個非零元素(因為0后面可能又接著是0),讓該元素和下標為index的元素交換,接著做index++;繼續往后遍歷,找到接下來的第一個非零元素,讓該元素和下標為index的元素交換,接著做index++......一直繼續執行該操作至遍歷到數組最后一個元素,大功告成!最差的情況下要交換n - 1 次,時間復雜度為O(n),比之前思考的那一個方法快了一個指數級。
這個問題我優化到這里了,希望大家可以思考到更好的方法。
二、甲上樓需要走20個階梯,每次可能走1步,也可能走2步。問有多少種走法?
我一開始的思路是排列組合里面的捆綁。拆解:1、假設沒有走兩步,那么便是1種走法。2、假設只走了一次兩步,那么把這兩步捆綁在一起,插在其它18步的任意一步的前面后者后面,那么總共有19種走法。3、假設走了兩次兩步,捆綁插入那么便是17 * 18 / 2種走法。。。繼續算下去至走了十次兩步。乍一看我這個方法還不錯,解決了問題,也能算出正確答案,但是有兩個缺點。缺點1:容易算錯,公式要用的比較細心。缺點2:如果題目是可能走1步,2步,也可能是3步,或者4步,那我這解法就要弄得更復雜才能解決這問題了。不能靈活變化的解法都不是好解法。
好解法當然還是有的,有人提醒我可以用動態規劃,其實它是一個斐波那契數列的應用。
原來如此!20步可能是19步+1步,也可能是18步+2步。那么f(20) = f(19) + f(18),我只要算19步的走法數加上18步的走法數就好了,而f(19) = f(18) + f(17),所以f(20) =?f(18) + f(17) +?f(18),繼續遞歸到右邊的式子都是f(2) 和f(1),那么問題也就只是個加法運算了。如果有走3步的可能,也同樣可以使用該方法。
三、有15個瓶子,其中最多有一瓶有毒,現在有四只老鼠,老鼠喝了有毒的水之后第二天就會死。如何在第二天就可以判斷出哪個瓶子有毒?
這個看到15瓶就知道怎么做了,最多一瓶有毒,所以共15+1=16種結果,而有4老鼠,用排列組合算一下就OK了。把老鼠編號A、B、C、D,把水編號1、2、3、4....14、15。解決方法:把1給A喝,2給B喝,3給C喝,4給D喝,5給A和B喝,6給A和C喝,7給A和D...10給C和D,11給A、B、C喝...14給B、C、D喝,15給所有老鼠都喝。
毒死1只老鼠:共4種。比如D死則4號水有毒。
毒死2只老鼠:共6種。比如A和D死則7號水有毒。
毒死3只老鼠:共4種。比如B、C、D死則14號水有毒。
毒死4只老鼠:共1種。15號水有毒。
毒死0只老師,共1種,也就是所有水都沒毒。
根據毒死的結果就可以知道是哪瓶有毒了。
四、給定能隨機生成整數 1 到 5 的函數,寫出能隨機生成整數 1 到 7 的函數。
看到題目是挺懵逼的,思考了很久想了一個答案,但沒有完美解決這個問題。
5的冪都不能被7整除,所以只能曲線救國。f(a) =?random(5)* ?5 -?random(5)+1 可以得到1-25的25個數其中的一個a,所有結果出現的概率相等。如果a是前面21個數除以3分別可以得到0-6其中的一個,如果是22-25中的其中一個,則再做一次f(a),再用剛才的判斷方法進行后續的步驟。
記錄到這里,加油!