Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 5a41329

Browse files
feat: add solutions to lc problem: No.464 (doocs#3055)
No.0464.Can I Win
1 parent ba1990e commit 5a41329

File tree

9 files changed

+261
-167
lines changed

9 files changed

+261
-167
lines changed

‎solution/0400-0499/0464.Can I Win/README.md‎

Lines changed: 89 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,20 @@ tags:
7575

7676
### 方法一:状态压缩 + 记忆化搜索
7777

78+
我们首先判断可以选择的所有整数的和是否小于目标值,如果是,说明无论如何都无法赢,直接返回 `false`
79+
80+
然后,我们设计一个函数 $\text{dfs}(mask, s),ドル其中 `mask` 表示当前已选择的整数的状态,`s` 表示当前的累计和。函数返回值为当前玩家是否能赢。
81+
82+
函数 $\text{dfs}(mask, s)$ 的执行过程如下:
83+
84+
我们遍历 1ドル$ 到 $maxChoosableInteger$ 中的每个整数 $i,ドル如果 $i$ 还没有被选择,我们可以选择 $i,ドル如果选择 $i$ 后的累计和 $s + i$ 大于等于目标值 `desiredTotal`,或者对手选择 $i$ 后的结果是输的,那么当前玩家就是赢的,返回 `true`
85+
86+
如果没有任何一个选择能让当前玩家赢,那么当前玩家就是输的,返回 `false`
87+
88+
为了避免重复计算,我们使用一个哈希表 `f` 记录已经计算过的状态,键为 `mask`,值为当前玩家是否能赢。
89+
90+
时间复杂度 $O(2^n),ドル空间复杂度 $O(2^n)$。其中 $n$ 是 `maxChoosableInteger`
91+
7892
<!-- tabs:start -->
7993

8094
#### Python3
@@ -83,16 +97,14 @@ tags:
8397
class Solution:
8498
def canIWin(self, maxChoosableInteger: int, desiredTotal: int) -> bool:
8599
@cache
86-
def dfs(state, t):
100+
def dfs(mask: int, s: int) -> bool:
87101
for i in range(1, maxChoosableInteger + 1):
88-
if (state >> i) & 1:
89-
continue
90-
if t + i >= desiredTotal or not dfs(state | 1 << i, t + i):
91-
return True
102+
if mask >> i & 1 ^ 1:
103+
if s + i >= desiredTotal or not dfs(mask | 1 << i, s + i):
104+
return True
92105
return False
93106

94-
s = (1 + maxChoosableInteger) * maxChoosableInteger // 2
95-
if s < desiredTotal:
107+
if (1 + maxChoosableInteger) * maxChoosableInteger // 2 < desiredTotal:
96108
return False
97109
return dfs(0, 0)
98110
```
@@ -101,32 +113,33 @@ class Solution:
101113

102114
```java
103115
class Solution {
104-
private Map<Integer, Boolean> memo = new HashMap<>();
116+
private Map<Integer, Boolean> f = new HashMap<>();
117+
private int maxChoosableInteger;
118+
private int desiredTotal;
105119

106120
public boolean canIWin(int maxChoosableInteger, int desiredTotal) {
107-
int s = (1 + maxChoosableInteger) * maxChoosableInteger / 2;
108-
if (s < desiredTotal) {
121+
if ((1 + maxChoosableInteger) * maxChoosableInteger / 2 < desiredTotal) {
109122
return false;
110123
}
111-
return dfs(0, 0, maxChoosableInteger, desiredTotal);
124+
this.maxChoosableInteger = maxChoosableInteger;
125+
this.desiredTotal = desiredTotal;
126+
return dfs(0, 0);
112127
}
113128

114-
private boolean dfs(int state, int t, intmaxChoosableInteger, intdesiredTotal) {
115-
if (memo.containsKey(state)) {
116-
return memo.get(state);
129+
private boolean dfs(int mask, int s) {
130+
if (f.containsKey(mask)) {
131+
return f.get(mask);
117132
}
118-
boolean res = false;
119-
for (int i = 1; i <= maxChoosableInteger; ++i) {
120-
if (((state >> i) & 1) == 0) {
121-
if (t + i >= desiredTotal
122-
|| !dfs(state | 1 << i, t + i, maxChoosableInteger, desiredTotal)) {
123-
res = true;
124-
break;
133+
for (int i = 0; i < maxChoosableInteger; ++i) {
134+
if ((mask >> i & 1) == 0) {
135+
if (s + i + 1 >= desiredTotal || !dfs(mask | 1 << i, s + i + 1)) {
136+
f.put(mask, true);
137+
return true;
125138
}
126139
}
127140
}
128-
memo.put(state, res);
129-
return res;
141+
f.put(mask, false);
142+
return false;
130143
}
131144
}
132145
```
@@ -137,24 +150,24 @@ class Solution {
137150
class Solution {
138151
public:
139152
bool canIWin(int maxChoosableInteger, int desiredTotal) {
140-
int s = (1 + maxChoosableInteger) * maxChoosableInteger / 2;
141-
if (s < desiredTotal) return false;
142-
unordered_map<int, bool> memo;
143-
return dfs(0, 0, maxChoosableInteger, desiredTotal, memo);
144-
}
145-
146-
bool dfs(int state, int t, int maxChoosableInteger, int desiredTotal, unordered_map<int, bool>& memo) {
147-
if (memo.count(state)) return memo[state];
148-
bool res = false;
149-
for (int i = 1; i <= maxChoosableInteger; ++i) {
150-
if ((state >> i) & 1) continue;
151-
if (t + i >= desiredTotal || !dfs(state | 1 << i, t + i, maxChoosableInteger, desiredTotal, memo)) {
152-
res = true;
153-
break;
154-
}
153+
if ((1 + maxChoosableInteger) * maxChoosableInteger / 2 < desiredTotal) {
154+
return false;
155155
}
156-
memo[state] = res;
157-
return res;
156+
unordered_map<int, int> f;
157+
function<bool(int, int)> dfs = [&](int mask, int s) {
158+
if (f.contains(mask)) {
159+
return f[mask];
160+
}
161+
for (int i = 0; i < maxChoosableInteger; ++i) {
162+
if (mask >> i & 1 ^ 1) {
163+
if (s + i + 1 >= desiredTotal || !dfs(mask | 1 << i, s + i + 1)) {
164+
return f[mask] = true;
165+
}
166+
}
167+
}
168+
return f[mask] = false;
169+
};
170+
return dfs(0, 0);
158171
}
159172
};
160173
```
@@ -163,33 +176,55 @@ public:
163176
164177
```go
165178
func canIWin(maxChoosableInteger int, desiredTotal int) bool {
166-
s := (1 + maxChoosableInteger) * maxChoosableInteger / 2
167-
if s < desiredTotal {
179+
if (1+maxChoosableInteger)*maxChoosableInteger/2 < desiredTotal {
168180
return false
169181
}
170-
memo := map[int]bool{}
182+
f := map[int]bool{}
171183
var dfs func(int, int) bool
172-
dfs = func(state, t int) bool {
173-
if v, ok := memo[state]; ok {
184+
dfs = func(mask, s int) bool {
185+
if v, ok := f[mask]; ok {
174186
return v
175187
}
176-
res := false
177188
for i := 1; i <= maxChoosableInteger; i++ {
178-
if (state>>i)&1 == 1 {
179-
continue
180-
}
181-
if t+i >= desiredTotal || !dfs(state|1<<i, t+i) {
182-
res = true
183-
break
189+
if mask>>i&1 == 0 {
190+
if s+i >= desiredTotal || !dfs(mask|1<<i, s+i) {
191+
f[mask] = true
192+
return true
193+
}
184194
}
185195
}
186-
memo[state] = res
187-
return res
196+
f[mask] = false
197+
return false
188198
}
189199
return dfs(0, 0)
190200
}
191201
```
192202

203+
#### TypeScript
204+
205+
```ts
206+
function canIWin(maxChoosableInteger: number, desiredTotal: number): boolean {
207+
if (((1 + maxChoosableInteger) * maxChoosableInteger) / 2 < desiredTotal) {
208+
return false;
209+
}
210+
const f: Record<string, boolean> = {};
211+
const dfs = (mask: number, s: number): boolean => {
212+
if (f.hasOwnProperty(mask)) {
213+
return f[mask];
214+
}
215+
for (let i = 1; i <= maxChoosableInteger; ++i) {
216+
if (((mask >> i) & 1) ^ 1) {
217+
if (s + i >= desiredTotal || !dfs(mask ^ (1 << i), s + i)) {
218+
return (f[mask] = true);
219+
}
220+
}
221+
}
222+
return (f[mask] = false);
223+
};
224+
return dfs(0, 0);
225+
}
226+
```
227+
193228
<!-- tabs:end -->
194229

195230
<!-- solution:end -->

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /