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

第一道:除數博弈

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

題目解析

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

  • 假設 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 爲偶數時, 愛麗絲獲勝code

是這樣嗎?索引

是的。three

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

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

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

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

  • 當她面對的 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 號問題:燈泡開關it

題目分析

首先,由於電燈一開始都是關閉的,因此某一盞燈最後若是是點亮的,必然要被按奇數次開關。

咱們假設只有 6 盞燈,並且咱們只看第 6 盞燈。須要進行 6 輪操做對吧,請問對於第 6 盞燈,會被按下幾回開關呢?這不可貴出,第 1 輪會被按,第 2 輪,第 3 輪,第 6 輪都會被按。

爲何第 一、二、三、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 堆的狀況下。設第1、第3、第5、第七樁是白色的,第2、第4、第6、第八樁是黑色的。 亞歷克斯老是能夠拿到全部白色樁或全部黑色樁,其中一種顏色具備的石頭數量一定大於另外一種顏色的。

所以,亞歷克斯總能贏得比賽。

代碼實現

class Solution {
    public boolean stoneGame(int[] piles) {
        return true;
    }
}複製代碼
相關文章
相關標籤/搜索