1. 程式人生 > >演算法中常見的Math類問題總結(一)

演算法中常見的Math類問題總結(一)

演算法中Math(數學類問題總結一)

  1. Nim Game(分石頭),A和B輪流分石頭,每人每次只能分1到3個,什麼樣的策略可以保證A總是贏的。

    思路:若是A第一個拿並且總的石頭數多於3,那麼希望最終留下的是4個,因為剩4個時,無論B怎麼拿,A都是贏的。若B第一個拿,那麼希望最終剩下的永遠不要是4。道理同上。
    If(n%4==1 || n%4==2 || n%4==3) return 1; else return 0;

  2. 求兩個數之和,但是不能使用+或者-。

    思路:既然題目要求不能用+或者—,那麼只能換種方式,最直接的就是想到用異或運算和&運算。若某位上的兩個數同時為1或者0,則異或後為0,若一個1,一個0,則異或後是1,這是加法運算中得到的正確結果。但是沒有考慮進位,當同時為1時,該為為0,但需要進位,此時我們再求兩個數的&運算,即為進位,並左移一位,講這個數和上面異或得到的數再遞迴上述類似的運算,直到&運算後為0,即沒有進位為止。
    getSum{ if(b==0) return a; c=a^b; d=a&b; getSum(c,d);}

  3. Single Number(在一個整數陣列中,每個數都出現兩次,只有一個數只出現了一次,找出這個數)

    思路:這種題目求和不行,最直接想到的就是進行位運算,再考慮用哪種位運算,我們知道兩個相同的數做^運算為0,那麼將所有的數做異或運算後,得到的就是隻出現一次的那個數了。由此題會引出很多類似的問題,大多都是不同的位運算結合來實現的。

  4. Majority Element(找出整個陣列中出現頻率最高的那個整數,並且出現的次數多於[n/2],並且)假設總有這樣的數存在的,個數多[n/2]的只有一個數。

    思路1:這道題最簡單的做法就是先給陣列排序,然後統計相等元素的個數,找出最多的那個。但是這樣時間複雜度太高,至少是O(nlogn)。
    思路2

    :用雜湊表實現。用map儲存,陣列中的當前元素的值為key,對應的他出現的次數為value,那麼最後找個value大與[n/2]的元素即可。
    思路3:位運算。假設資料的數值範圍是(1,2^32-1),那麼我們可以用32位來表示任何一個數。也就相當於一個大小為32的陣列來標記各個元素在每個位上出現的次數,最後將32位中次數大於[n/2]的刪選出來,轉換為十進位制,即為所求。

  5. Contains Duplicate(判斷陣列中是否存在重複的兩個元素,若有返回ture,否則false)。

    思路:這道題很簡單,用set或者hashmap都可以快速實現。Set中每個元素只出現一遍,最後判斷set的大小和陣列的大小是否一樣即可。而map可以判斷是否已經存在這個元素就OK啦。

  6. Add Digits(求數字各個位之和,直到變為一個數為止。例如:38: 3+8=11;1+1=2)

    思路:這題目剛開始看上去,我能想到的就是迴圈或者遞迴了,一次一次的遍歷求,但是題目的要求確是不能用any loop or recursion。然後就蒙了,想了很久沒思路。但是這種題肯定是存在某種規律的,在1到9之間不停地迴圈。之後看了大神們的解答,果然是這樣。0單獨考慮外,從1開始,數字之和不停地在1到9之間迴圈,那麼如果這個數是9的倍數,他的最終結果是9,其他的就是n%9的結果了。原來如此簡單,功夫不夠,還得多練啊。
    If(n==0) return 0; m = n%9; if(m==0) return 9; else return m;

  7. Move Zeros(把一個數組中的0全部挪到最後面去,保持陣列其他元素的相對位置不變,例如:nums=[0,1,0,3,12]),最後得到nums=[1,3,12,0,0]; 並且只能用替換的方法實現。

    思路:這道題很簡單,設定兩個指標,從頭開始,一個是遍歷舊陣列,遇到一次判斷是不是0,另一個負責記錄新的陣列,講不是0的全部替換到該指標指向的當前位置。如下:
    ( A -> 1; B -> 2; C -> 3 … Z -> 26 AA -> 27 AB -> 28)
    思路:這道題其實和十進位制的規律一模一樣,變形的26進位制數。給了一個字串,計算得到是第幾列,也就是把字串轉化為對應的整數。(a[0]-‘A’+1)26+(a[1]-‘A’+1); 更直白的表達:如果是十進位制的數1342: 1(10^3)+3*(10^2)+4*(10^1)+2+(10^0); 對應於二十六進位制的數: ABCD:1*(26^3)+2*(26^2)+3*(26^1)+4*(26^0).

  8. Power of Two(判斷一個數是不是2的冪) num&(num-1) == 0 (這個最簡單)

    思路1:第一反應想到的應該是二進位制,把2,4,8,16,32等2的冪轉換成2進賬可以發現,最高位為1,後面的全部為0。根據這個規律我們可以把n轉換為二進位制的字串,此時最低位對應的數字裡的最高位,我們只需要判斷最低位是否為1,並且其他為是否全部為0。
    思路2:判斷一個數的冪可以轉換為對數來算,用換底公式,log以10為底的n除以log以10位底的2,此時是double型的,減去它的int型,看是否為0,若是整數,則是2的冪。
    注意:由於整數的最小值即Integer.MinValue轉換為二進位制是不是正常的,需要單獨考慮,直接返回false。寫這種數字題時,切記注意考慮0,1,最大最小數這些敏感的數,做到萬無一失。

  9. Power of Three(判斷一個數是不是3的冪)

    思路: 同上,用對數的方法判斷。

  10. Power of Four(判斷一個數是不是4的冪)

    思路:除了上面的換地公式,我們還可以借鑑2的思路來考慮這道題。
    首先先判斷是不是2的冪,是2的冪之後再判斷與10101010101 做&運算是不是其本身。

  11. Happy Number(這道題定義了一種快樂數,就是說對於某一個正整數,如果對其各個位上的數字分別平方,然後再加起來得到一個新的數字,再進行同樣的操作,如果最終結果變成了1,則說明是快樂數,如果一直迴圈但不是1的話,就不是快樂數,那麼現在任意給我們一個正整數,讓我們判斷這個數是不是快樂數。)

    思路:拿到這種題用肉眼看不出思路,那麼就多試幾個數,找找規律。果然會發現,在迴圈中必定會出現1和4,而且4繼續迴圈的話還會回到4,重複上述過程,這時的數就不是快樂數了,直接返回false,若是1的話就返回true;當然,如果沒發現這個規律的話,我們可以用set,將每次得到的結果儲存起來,若是再出現的話那一定是開始迴圈了,則返回,否則繼續。這種題,如果要是用很嚴格的數學證明結論的話,那比較難,希望有一天可以達到這種水平。

  12. Ugly Number(定義為一個數的質因素只包含2,3,5)

    思路:這道題很簡單,最直接的思路就是直接用該數不停地除以2,直到不能整除為止,同理,再除以3,5。看最終結果是不是為1。

  13. Number of 1 bits(一個無符號整數,返回其二進位制形式中包含的1的個數)

    思路:位運算。每次判斷整數n的最後一位是不是1,即讓n&1,之後將n右移一位。直到n=0。