Skip to content

464. Can I Win 👍

  • Time: $O(n \codt turns)$
  • Space: $O(n)$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
 public:
  bool canIWin(int maxChoosableInteger, int desiredTotal) {
    if (desiredTotal <= 0)
      return true;

    const int sum = maxChoosableInteger * (maxChoosableInteger + 1) / 2;
    if (sum < desiredTotal)
      return false;

    return dp(desiredTotal, 0, maxChoosableInteger);
  }

 private:
  unordered_map<int, bool> memo;  // true := can win, false := can't win

  bool dp(int total, int bitmask, int n) {
    if (total <= 0)
      return false;
    if (const auto it = memo.find(bitmask); it != memo.cend())
      return it->second;

    for (int i = 1; i <= n; ++i) {
      if (bitmask & 1 << i)  // Integer i is used.
        continue;
      if (!dp(total - i, bitmask | 1 << i, n))
        return true;
    }

    return memo[bitmask] = false;
  }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
  public boolean canIWin(int maxChoosableInteger, int desiredTotal) {
    if (desiredTotal <= 0)
      return true;

    final int sum = maxChoosableInteger * (maxChoosableInteger + 1) / 2;
    if (sum < desiredTotal)
      return false;

    return dp(desiredTotal, 0, maxChoosableInteger);
  }

  // true := can win, false := can't win
  private Map<Integer, Boolean> memo = new HashMap<>();

  private boolean dp(int total, int bitmask, int n) {
    if (total <= 0)
      return false;
    if (memo.containsKey(bitmask))
      return memo.get(bitmask);

    for (int i = 1; i <= n; ++i) {
      if ((bitmask & 1 << i) == 1) // Integer i is used.
        continue;
      if (!dp(total - i, bitmask | 1 << i, n))
        return true;
    }

    memo.put(bitmask, false);
    return false;
  }
}