75
75
76
76
### 方法一:状态压缩 + 记忆化搜索
77
77
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
+
78
92
<!-- tabs:start -->
79
93
80
94
#### Python3
@@ -83,16 +97,14 @@ tags:
83
97
class Solution :
84
98
def canIWin (self , maxChoosableInteger : int , desiredTotal : int ) -> bool :
85
99
@cache
86
- def dfs (state , t ) :
100
+ def dfs (mask : int , s : int ) -> bool :
87
101
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
92
105
return False
93
106
94
- s = (1 + maxChoosableInteger) * maxChoosableInteger // 2
95
- if s < desiredTotal:
107
+ if (1 + maxChoosableInteger) * maxChoosableInteger // 2 < desiredTotal:
96
108
return False
97
109
return dfs(0 , 0 )
98
110
```
@@ -101,32 +113,33 @@ class Solution:
101
113
102
114
``` java
103
115
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;
105
119
106
120
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) {
109
122
return false ;
110
123
}
111
- return dfs(0 , 0 , maxChoosableInteger, desiredTotal);
124
+ this . maxChoosableInteger = maxChoosableInteger;
125
+ this . desiredTotal = desiredTotal;
126
+ return dfs(0 , 0 );
112
127
}
113
128
114
- private boolean dfs (int state , int t , int maxChoosableInteger , int desiredTotal ) {
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 );
117
132
}
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 ;
125
138
}
126
139
}
127
140
}
128
- memo . put(state, res );
129
- return res ;
141
+ f . put(mask, false );
142
+ return false ;
130
143
}
131
144
}
132
145
```
@@ -137,24 +150,24 @@ class Solution {
137
150
class Solution {
138
151
public:
139
152
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;
155
155
}
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);
158
171
}
159
172
};
160
173
```
@@ -163,33 +176,55 @@ public:
163
176
164
177
```go
165
178
func canIWin(maxChoosableInteger int, desiredTotal int) bool {
166
- s := (1 + maxChoosableInteger) * maxChoosableInteger / 2
167
- if s < desiredTotal {
179
+ if (1+maxChoosableInteger)*maxChoosableInteger/2 < desiredTotal {
168
180
return false
169
181
}
170
- memo := map [int ]bool {}
182
+ f := map[int]bool{}
171
183
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 {
174
186
return v
175
187
}
176
- res := false
177
188
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
+ }
184
194
}
185
195
}
186
- memo[state ] = res
187
- return res
196
+ f[mask ] = false
197
+ return false
188
198
}
189
199
return dfs(0, 0)
190
200
}
191
201
```
192
202
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
+
193
228
<!-- tabs: end -->
194
229
195
230
<!-- solution: end -->
0 commit comments