LeetCode 上一行代碼就能解決的智力算法題

第一道:除數博弈

題目來源於 LeetCode 上第 1025 號問題:除數博弈

題目解析

對於這種博弈類的題目,如果沒有思路的話我們不妨多舉幾個例子,嘗試着從中找尋規律。

  • 假設 N = 1,愛麗絲沒得選擇,直接失敗,即 鮑勃獲勝
  • 假設 N = 2,愛麗絲有選擇,她可以選擇 x = 1,鮑勃面對的就是 N = 2 - 1 = 1,無法操作,愛麗絲獲勝
  • 假設 N = 3,愛麗絲只能選擇 x = 1,因爲選 x = 2 不滿足 3 % 2 = 0,鮑勃面對的就是 N = 3 - 1 = 2,參考上面 N = 2 的情形,此時鮑勃爲 N = 2 的先手,鮑勃獲勝
  • 假設 N = 4,愛麗絲可以選擇 x = 1 來使鮑勃遇到 N = 3 的情況,愛麗絲獲勝

貌似有個規律:N 爲奇數時, 鮑勃獲勝;N 爲偶數時, 愛麗絲獲勝

是這樣嗎?

是的。

事實上,無論 N 爲多大,最終都是在 N = 2 這個臨界點結束的。誰最後面對的是 N = 2 的情形,誰就能獲勝(這句話不太理解的話,仔細看看 N = 2、N = 3 這兩種情形)。

接下來,我們得知道一個數學小知識:奇數的因子(約數)只能是奇數,偶數的因子(約數)可以是奇數或偶數

千萬不要忽略 1 也是因子!

愛麗絲是遊戲開始時的先手。

  • 當她面對的 N 爲偶數時,她 一定可以 選到一個 N 的奇數因子 x(比如 1 ),將 N - x 這個奇數傳給鮑勃;用 N - x 替換黑板上的數字 N ,鮑勃面對的就是奇數 N,只能選擇 N 的奇數因子 x,奇數 - 奇數 = 偶數,此時傳給愛麗絲的又是偶數。這樣輪換下去愛麗絲會遇到 N = 2 的情形,然後獲勝;
  • 當愛麗絲遇到的 N 是奇數時,只能傳給鮑勃偶數或無法操作 (N = 1) ,無法獲勝。

代碼實現

//@五分鐘學算法
class Solution {
    public boolean divisorGame(int N) {
        return N % 2 == 0;
    }
}

第二道:燈泡開關

題目來源於 LeetCode 上第 319 號問題:燈泡開關

題目分析

首先,因爲電燈一開始都是關閉的,所以某一盞燈最後如果是點亮的,必然要被按奇數次開關。

我們假設只有 6 盞燈,而且我們只看第 6 盞燈。需要進行 6 輪操作對吧,請問對於第 6 盞燈,會被按下幾次開關呢?這不難得出,第 1 輪會被按,第 2 輪,第 3 輪,第 6 輪都會被按。

爲什麼第 1、2、3、6 輪會被按呢?因爲 6 = 1×6 = 2×3。一般情況下,因子都是成對出現的,也就是說開關被按的次數一般是偶數次。但是有特殊情況,比如說總共有 16 盞燈,那麼第 16 盞燈會被按幾次?

16 = 1 × 16 = 2 × 8 = 4 × 4 

其中因子 4 重複出現,所以第 16 盞燈會被按 5 次,奇數次。現在你應該理解這個問題爲什麼和平方根有關了吧?

不過,我們不是要算最後有幾盞燈亮着嗎,這樣直接平方根一下是啥意思呢?稍微思考一下就能理解了。

就假設現在總共有 16 盞燈,我們求 16 的平方根,等於 4,這就說明最後會有 4 盞燈亮着,它們分別是第 1 × 1 = 1 盞、第 2 × 2=4 盞、第 3 × 3 = 9 盞和第 4 × 4 = 16盞。

我們不是想求有多少個可開方的數嗎,4 是最大的平方根,那麼小於 4 的正整數的平方都是在 1~16 內的,是會被按奇數次開關,最終亮着的燈。

就算有的 n 平方根結果是小數,強轉成 int 型,也相當於一個最大整數上界,比這個上界小的所有整數,平方後的索引都是最後亮着的燈的索引。所以說我們直接把平方根轉成整數,就是這個問題的答案。

代碼實現

class Solution {
    public int bulbSwitch(int n) {
         return (int)Math.sqrt(n);
    }
}

第三道:3的冪

題目來源於 LeetCode 上第 326 號問題:3的冪

題目解析

正常的思路是不停地去除以 3,看最後的迭代商是否爲 1。這種思路的代碼使用到了循環,逼格不夠高。

這裏取巧的方法 用到了數論的知識:3 的冪次的質因子只有 3

題目要求輸入的是 int 類型,正數範圍是 0 - 231,在此範圍中允許的最大的 3 的次方數爲 319 = 1162261467 ,那麼只要看這個數能否被 n 整除即可。

代碼實現

//@五分鐘學算法
class Solution {
    public boolean isPowerOfThree(int n) {
         return n > 0 && 1162261467 % n == 0;
    }
}

第四道:2的冪

題目來源於 LeetCode 上第 231 號問題:2的冪

題目解析

如果一個數是 2 的次方數的話,那麼它的二進數必然是最高位爲 1,其它都爲 0 ,那麼如果此時我們減 1 的話,則最高位會降一位,其餘爲 0 的位現在都爲變爲 1,那麼我們把兩數相與,就會得到 0。

代碼實現

//@五分鐘學算法
class Solution {
public:
    bool isPowerOfTwo(int n) {
          return n > 0 && ((n & (n - 1)) == 0);
    } 
};

第五道:階乘後的零

題目來源於 LeetCode 上第 172 號問題:階乘後的零

題目解析

題目很好理解,數階乘後的數字末尾有多少個零。

最簡單粗暴的方法就是先乘完再說,然後一個一個數。

事實上,你在使用暴力破解法的過程中就能發現規律: 這 9 個數字中只有 2(它的倍數) 與 5 (它的倍數)相乘纔有 0 出現

所以,現在問題就變成了這個階乘數中能配 多少對 2 與 5

舉個複雜點的例子:

10! = 【 2 *( 2 * 2 )* 5 *( 2 * 3 )*( 2 * 2 * 2 )*( 2 * 5)】

在 10!這個階乘數中可以匹配兩對 2 * 5 ,所以10!末尾有 2 個 0。

可以發現,一個數字進行拆分後 2 的個數肯定是大於 5 的個數的,所以能匹配多少對取決於 5 的個數。(好比現在男女比例懸殊,最多能有多少對異性情侶取決於女生的多少)。

那麼問題又變成了 統計階乘數裏有多少個 5 這個因子

需要注意的是,像 25,125 這樣的不只含有一個 5 的數字的情況需要考慮進去。

比如 n = 15。那麼在 15! 中 有 35 (來自其中的5, 10, 15), 所以計算 n/5 就可以 。

但是比如 n=25,依舊計算 n/5 ,可以得到 55,分別來自其中的5, 10, 15, 20, 25,但是在 25 中其實是包含 2 5 的,這一點需要注意。

所以除了計算 n/5 , 還要計算 n/5/5 , n/5/5/5 , n/5/5/5/5 , ..., n/5/5/5,,,/5直到商爲0,然後求和即可。

代碼實現

//@五分鐘學算法
public class Solution {
    public int trailingZeroes(int n) {
        return n == 0 ? 0 : n / 5 + trailingZeroes(n / 5);
    }
}

第六道:Nim 遊戲

題目來源於 LeetCode 上第 292 號問題:Nim 遊戲

題目解析

我們解決這種問題的思路一般都是反着思考:

如果我能贏,那麼最後輪到我取石子的時候必須要剩下 1~3 顆石子,這樣我才能一把拿完。

如何營造這樣的一個局面呢?顯然,如果對手拿的時候只剩 4 顆石子,那麼無論他怎麼拿,總會剩下 1~3 顆石子,我就能贏。

如何逼迫對手面對 4 顆石子呢?要想辦法,讓我選擇的時候還有 5~7 顆石子,這樣的話我就有把握讓對方不得不面對 4 顆石子。

如何營造 5~7 顆石子的局面呢?讓對手面對 8 顆石子,無論他怎麼拿,都會給我剩下 5~7 顆,我就能贏。

這樣一直循環下去,我們發現只要踩到 4 的倍數,就落入了圈套,永遠逃不出 4 的倍數,而且一定會輸。

代碼實現

public class Solution {
   bool canWinNim(int n) {
    // 如果上來就踩到 4 的倍數,那就認輸吧
    // 否則,可以把對方控制在 4 的倍數,必勝
    return n % 4 != 0;
    }
}

第七道:石子游戲

題目來源於 LeetCode 上第 877 號問題:石子游戲

題目解析

顯然,亞歷克斯總是贏得 2 堆時的遊戲。 通過一些努力,我們可以獲知她總是贏得 4 堆時的遊戲。

如果亞歷克斯最初獲得第一堆,她總是可以拿第三堆。 如果她最初取到第四堆,她總是可以取第二堆。第一 + 第三,第二 + 第四 中的至少一組是更大的,所以她總能獲勝。

我們可以將這個想法擴展到 N 堆的情況下。設第一、第三、第五、第七樁是白色的,第二、第四、第六、第八樁是黑色的。 亞歷克斯總是可以拿到所有白色樁或所有黑色樁,其中一種顏色具有的石頭數量必定大於另一種顏色的。

因此,亞歷克斯總能贏得比賽。

代碼實現

class Solution {
    public boolean stoneGame(int[] piles) {
        return true;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章