[LeetCode] 464. Can I Win 我能贏嗎


 

In the "100 game," two players take turns adding, to a running total, any integer from 1..10. The player who first causes the running total to reach or exceed 100 wins.

What if we change the game so that players cannot re-use integers?

For example, two players might take turns drawing from a common pool of numbers of 1..15 without replacement until they reach a total >= 100.

Given an integer maxChoosableInteger and another integer desiredTotal, determine if the first player to move can force a win, assuming both players play optimally.

You can always assume that maxChoosableInteger will not be larger than 20 and desiredTotal will not be larger than 300.

Example

Input:
maxChoosableInteger = 10
desiredTotal = 11

Output:
false

Explanation:
No matter which integer the first player choose, the first player will lose.
The first player can choose an integer from 1 up to 10.
If the first player choose 1, the second player can only choose integers from 2 up to 10.
The second player will win by choosing 10 and get a total = 11, which is >= desiredTotal.
Same with other integers chosen by the first player, the second player will always win.

 

這道題給了我們一堆數字,然后兩個人,每人每次選一個數字,看數字總數誰先到給定值,有點像之前那道 Nim Game,但是比那題難度大。我剛開始想肯定說用遞歸啊,結果寫完發現 TLE 了,后來發現我們必須要優化效率,使用 HashMap 來記錄已經計算過的結果。我們首先來看如果給定的數字范圍大於等於目標值的話,直接返回 true。如果給定的數字總和小於目標值的話,說明誰也沒法贏,返回 false。然后我們進入遞歸函數,首先我們查找當前情況是否在 HashMap 中存在,有的話直接返回即可。我們使用一個整型數按位來記錄數組中的某個數字是否使用過,我們遍歷所有數字,將該數字對應的 mask 算出來,如果其和 used 相與為0的話,說明該數字沒有使用過,我們看如果此時的目標值小於等於當前數字,說明已經贏了,或者調用遞歸函數,如果返回 false,說明也是第一個人贏了。為啥呢,因為當前已經選過數字了,此時就該對第二個人調用遞歸函數,只有返回的結果是 false,我們才能贏,所以此時我們 true,並返回 true。如果遍歷完所有數字,標記 false,並返回 false,參見代碼如下:

 

class Solution {
public:
    bool canIWin(int maxChoosableInteger, int desiredTotal) {
        if (maxChoosableInteger >= desiredTotal) return true;
        if (maxChoosableInteger * (maxChoosableInteger + 1) / 2 < desiredTotal) return false;
        unordered_map<int, bool> m;
        return canWin(maxChoosableInteger, desiredTotal, 0, m);
    }
    bool canWin(int length, int total, int used, unordered_map<int, bool>& m) {
        if (m.count(used)) return m[used];
        for (int i = 0; i < length; ++i) {
            int cur = (1 << i);
            if ((cur & used) == 0) {
                if (total <= i + 1 || !canWin(length, total - (i + 1), cur | used, m)) {
                    m[used] = true;
                    return true;
                }
            }
        }
        m[used] = false;
        return false;
    }
};

 

Github 同步地址:

https://github.com/grandyang/leetcode/issues/464

 

類似題目:

Nim Game

Flip Game II   

Guess Number Higher or Lower II 

Predict the Winner

 

參考資料:

https://leetcode.com/problems/can-i-win/

https://leetcode.com/problems/can-i-win/discuss/95283/brute-force-and-memoization

https://leetcode.com/problems/can-i-win/discuss/95277/Java-solution-using-HashMap-with-detailed-explanation

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM