1. 程式人生 > >[leetcode] 464. Can I Win (Medium)

[leetcode] 464. Can I Win (Medium)

原題連結


兩個人依次從1~maxNum中選取數字(不可重複選取同一個),累和。當一方選取數字累和後結果大於等於給定的目標數字,則此人勝利。
題目給一個maxNum和targetNum,要求判斷先手能否勝利。

思路:
首先判斷兩種特殊條件:

  1. 可選最大值大於等於目標值,直接返回true。
  2. 其中一個人可選的最大值小於目標值,直接返回false。

具體再看題目,題目給出maxNum不大於20,則可狀態壓縮為一個int(32位)來儲存每個數字是否被使用過(題解中利用1-32位進行儲存)。
利用一個map儲存選取每一個數字的情況,每一次選擇前進行判斷,如若已經有過選取該數字的情況,則返回map裡的值。
遍歷i從1到maxN,考慮選取i的情況:
判斷先手勝利條件:

  1. 選上i數字後,大於等於目標值可勝利。( i >= targetN )
  2. 選上i數字後,後手輸了。( helper(maxN, targetN - i, mask | visited) == false) )
    返回true。
    其他情況下,則表示先手輸,返回false。

Runtime: 137 ms, faster than 43.48% of Java

class Solution {
    public Map<Integer, Boolean> m = new HashMap<Integer, Boolean>();

    public boolean helper(int maxN, int targetN, int visited) {
        if (m.containsKey(visited))
            return m.get(visited);
        for (int i = 1; i <= maxN; i++) {
            int mask = (1 << i);
            if ((mask & visited) == 0 && (i >= targetN || helper(maxN, targetN - i, mask | visited) == false)) {
                m.put(visited, true);
                return true;
            }
        }
        m.put(visited, false);
        return false;
    }

    public boolean canIWin(int maxChoosableInteger, int desiredTotal) {
        if (maxChoosableInteger >= desiredTotal)
            return true;
        if ((1 + maxChoosableInteger) * maxChoosableInteger / 2 < desiredTotal)
            return false;
        return helper(maxChoosableInteger, desiredTotal, 0);
    }
}