Skip to content

Commit f8f129d

Browse files
committed
feat: add solutions to lc problem: No.0794
No.0794.Valid Tic-Tac-Toe State
1 parent 645d18e commit f8f129d

File tree

9 files changed

+335
-275
lines changed

9 files changed

+335
-275
lines changed

solution/0700-0799/0792.Number of Matching Subsequences/README.md

+2-11
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949

5050
**方法一:分桶**
5151

52-
题目中字符串 $s$ 的数据规模最高达到 $5 \times 10^4$,如果暴力枚举 $words$ 中的每个字符串 $w$,判断其是否为 $s$ 的子序列,必然会超时
52+
题目中字符串 $s$ 的数据规模最高达到 $5 \times 10^4$,如果暴力枚举 $words$ 中的每个字符串 $w$,判断其是否为 $s$ 的子序列,很有可能会超时
5353

5454
我们不妨将 $words$ 中的所有单词根据首字母来分桶,即:把所有单词按照首字母分到 $26$ 个桶中,每个桶中存储的是所有以该字母开头的所有单词。
5555

@@ -60,7 +60,7 @@ a: ["a", "acd", "ace"]
6060
b: ["bb"]
6161
```
6262

63-
然后我们从 $s$ 的第一个字符开始遍历,假设当前字符为 `'a'`,我们从 `'a'` 开头的桶中取出所有单词。对于取出的每个单词,如果此时单词长度为 $1$,说明该单词已经匹配完毕,我们将答案加 $1$;否则我们将单词的首字母去掉,然后放入下一个字母开头的桶中,比如对于单词 `acd`,去掉首字母 `'a'` 后,我们将其放入 `'c'` 开头的桶中。这一轮结束后,分桶结果变为:
63+
然后我们从 $s$ 的第一个字符开始遍历,假设当前字符为 `'a'`,我们从 `'a'` 开头的桶中取出所有单词。对于取出的每个单词,如果此时单词长度为 $1$,说明该单词已经匹配完毕,我们将答案加 $1$;否则我们将单词的首字母去掉,然后放入下一个字母开头的桶中,比如对于单词 `"acd"`,去掉首字母 `'a'` 后,我们将其放入 `'c'` 开头的桶中。这一轮结束后,分桶结果变为:
6464

6565
```text
6666
c: ["cd", "ce"]
@@ -132,8 +132,6 @@ class Solution:
132132
def check(w):
133133
i = -1
134134
for c in w:
135-
if c not in d:
136-
return False
137135
j = bisect_right(d[c], i)
138136
if j == len(d[c]):
139137
return False
@@ -229,9 +227,6 @@ class Solution {
229227
int i = -1;
230228
for (int k = 0; k < w.length(); ++k) {
231229
int c = w.charAt(k) - 'a';
232-
if (d[c].isEmpty()) {
233-
return false;
234-
}
235230
int j = search(d[c], i);
236231
if (j == d[c].size()) {
237232
return false;
@@ -311,7 +306,6 @@ public:
311306
int i = -1;
312307
for (char& c : w) {
313308
auto& t = d[c - 'a'];
314-
if (t.empty()) return false;
315309
int j = upper_bound(t.begin(), t.end(), i) - t.begin();
316310
if (j == t.size()) return false;
317311
i = t[j];
@@ -380,9 +374,6 @@ func numMatchingSubseq(s string, words []string) (ans int) {
380374
i := -1
381375
for _, c := range w {
382376
t := d[c-'a']
383-
if len(t) == 0 {
384-
return false
385-
}
386377
j := sort.SearchInts(t, i+1)
387378
if j == len(t) {
388379
return false

solution/0700-0799/0792.Number of Matching Subsequences/README_EN.md

-9
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,6 @@ class Solution:
8585
def check(w):
8686
i = -1
8787
for c in w:
88-
if c not in d:
89-
return False
9088
j = bisect_right(d[c], i)
9189
if j == len(d[c]):
9290
return False
@@ -180,9 +178,6 @@ class Solution {
180178
int i = -1;
181179
for (int k = 0; k < w.length(); ++k) {
182180
int c = w.charAt(k) - 'a';
183-
if (d[c].isEmpty()) {
184-
return false;
185-
}
186181
int j = search(d[c], i);
187182
if (j == d[c].size()) {
188183
return false;
@@ -262,7 +257,6 @@ public:
262257
int i = -1;
263258
for (char& c : w) {
264259
auto& t = d[c - 'a'];
265-
if (t.empty()) return false;
266260
int j = upper_bound(t.begin(), t.end(), i) - t.begin();
267261
if (j == t.size()) return false;
268262
i = t[j];
@@ -331,9 +325,6 @@ func numMatchingSubseq(s string, words []string) (ans int) {
331325
i := -1
332326
for _, c := range w {
333327
t := d[c-'a']
334-
if len(t) == 0 {
335-
return false
336-
}
337328
j := sort.SearchInts(t, i+1)
338329
if j == len(t) {
339330
return false

solution/0700-0799/0794.Valid Tic-Tac-Toe State/README.md

+118-83
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,17 @@
6060

6161
<!-- 这里可写通用的实现逻辑 -->
6262

63+
**方法一:分类讨论**
64+
65+
我们先统计当前棋盘上 `'X'``'O'` 的数量,记为 $x$ 和 $o$。接下来,我们分情况讨论:
66+
67+
- 如果 $x \neq o$ 且 $x - 1 \neq o$,则当前棋盘不可能是有效棋盘,返回 `false`
68+
- 如果当前棋盘上玩家 1 获胜,但 $x-1 \neq o$,则当前棋盘不可能是有效棋盘,返回 `false`
69+
- 如果当前棋盘上玩家 2 获胜,但 $x \neq o$,则当前棋盘不可能是有效棋盘,返回 `false`
70+
- 其他情况下,当前棋盘是有效棋盘,返回 `true`
71+
72+
时间复杂度 $O(C)$,空间复杂度 $O(1)$。其中 $C$ 是棋盘上的格子数。本题中 $C = 9$。
73+
6374
<!-- tabs:start -->
6475

6576
### **Python3**
@@ -69,30 +80,22 @@
6980
```python
7081
class Solution:
7182
def validTicTacToe(self, board: List[str]) -> bool:
72-
def win(p):
83+
def win(x):
7384
for i in range(3):
74-
if board[i][0] == board[i][1] == board[i][2] == p:
85+
if all(board[i][j] == x for j in range(3)):
7586
return True
76-
if board[0][i] == board[1][i] == board[2][i] == p:
87+
if all(board[j][i] == x for j in range(3)):
7788
return True
78-
if board[0][0] == board[1][1] == board[2][2] == p:
89+
if all(board[i][i] == x for i in range(3)):
7990
return True
80-
return board[0][2] == board[1][1] == board[2][0] == p
81-
82-
x, o = 0, 0
83-
for i in range(3):
84-
for j in range(3):
85-
if board[i][j] == 'X':
86-
x += 1
87-
elif board[i][j] == 'O':
88-
o += 1
91+
return all(board[i][2 - i] == x for i in range(3))
8992

93+
x = sum(board[i][j] == 'X' for i in range(3) for j in range(3))
94+
o = sum(board[i][j] == 'O' for i in range(3) for j in range(3))
9095
if x != o and x - 1 != o:
9196
return False
92-
9397
if win('X') and x - 1 != o:
9498
return False
95-
9699
return not (win('O') and x != o)
97100
```
98101

@@ -102,121 +105,153 @@ class Solution:
102105

103106
```java
104107
class Solution {
108+
private String[] board;
109+
105110
public boolean validTicTacToe(String[] board) {
106-
int x = 0, o = 0;
107-
for (int i = 0; i < 3; i++) {
108-
for (int j = 0; j < 3; j++) {
109-
if (board[i].charAt(j) == 'X') {
110-
x++;
111-
} else if (board[i].charAt(j) == 'O') {
112-
o++;
113-
}
114-
}
115-
}
111+
this.board = board;
112+
int x = count('X'), o = count('O');
116113
if (x != o && x - 1 != o) {
117114
return false;
118115
}
119-
if (win(board, 'X') && x - 1 != o) {
116+
if (win('X') && x - 1 != o) {
120117
return false;
121118
}
122-
return !(win(board, 'O') && x != o);
119+
return !(win('O') && x != o);
123120
}
124121

125-
private boolean win(String[] b, char p) {
126-
for (int i = 0; i < 3; i++) {
127-
if (b[i].charAt(0) == p && b[i].charAt(1) == p && b[i].charAt(2) == p) {
122+
private boolean win(char x) {
123+
for (int i = 0; i < 3; ++i) {
124+
if (board[i].charAt(0) == x && board[i].charAt(1) == x && board[i].charAt(2) == x) {
128125
return true;
129126
}
130-
if (b[0].charAt(i) == p && b[1].charAt(i) == p && b[2].charAt(i) == p) {
127+
if (board[0].charAt(i) == x && board[1].charAt(i) == x && board[2].charAt(i) == x) {
131128
return true;
132129
}
133130
}
134-
if (b[0].charAt(0) == p && b[1].charAt(1) == p && b[2].charAt(2) == p) {
131+
if (board[0].charAt(0) == x && board[1].charAt(1) == x && board[2].charAt(2) == x) {
135132
return true;
136133
}
137-
return b[0].charAt(2) == p && b[1].charAt(1) == p && b[2].charAt(0) == p;
134+
return board[0].charAt(2) == x && board[1].charAt(1) == x && board[2].charAt(0) == x;
135+
}
136+
137+
private int count(char x) {
138+
int cnt = 0;
139+
for (var row : board) {
140+
for (var c : row.toCharArray()) {
141+
if (c == x) {
142+
++cnt;
143+
}
144+
}
145+
}
146+
return cnt;
138147
}
139148
}
140149
```
141150

151+
### **C++**
152+
153+
```cpp
154+
class Solution {
155+
public:
156+
bool validTicTacToe(vector<string>& board) {
157+
auto count = [&](char x) {
158+
int ans = 0;
159+
for (auto& row : board) for (auto& c : row) ans += c == x;
160+
return ans;
161+
};
162+
auto win = [&](char x) {
163+
for (int i = 0; i < 3; ++i) {
164+
if (board[i][0] == x && board[i][1] == x && board[i][2] == x) return true;
165+
if (board[0][i] == x && board[1][i] == x && board[2][i] == x) return true;
166+
}
167+
if (board[0][0] == x && board[1][1] == x && board[2][2] == x) return true;
168+
return board[0][2] == x && board[1][1] == x && board[2][0] == x;
169+
};
170+
int x = count('X'), o = count('O');
171+
if (x != o && x - 1 != o) return false;
172+
if (win('X') && x - 1 != o) return false;
173+
return !(win('O') && x != o);
174+
}
175+
};
176+
```
177+
142178
### **Go**
143179
144180
```go
145181
func validTicTacToe(board []string) bool {
146-
x, o := 0, 0
147-
for i := 0; i < 3; i++ {
148-
for j := 0; j < 3; j++ {
149-
if board[i][j] == 'X' {
182+
var x, o int
183+
for _, row := range board {
184+
for _, c := range row {
185+
if c == 'X' {
150186
x++
151-
} else if board[i][j] == 'O' {
187+
} else if c == 'O' {
152188
o++
153189
}
154190
}
155191
}
156-
if x != o && x-1 != o {
157-
return false
158-
}
159-
if win(board, 'X') && x-1 != o {
160-
return false
161-
}
162-
return !(win(board, 'O') && x != o)
163-
}
164-
165-
func win(b []string, p byte) bool {
166-
for i := 0; i < 3; i++ {
167-
if b[i][0] == p && b[i][1] == p && b[i][2] == p {
168-
return true
192+
win := func(x byte) bool {
193+
for i := 0; i < 3; i++ {
194+
if board[i][0] == x && board[i][1] == x && board[i][2] == x {
195+
return true
196+
}
197+
if board[0][i] == x && board[1][i] == x && board[2][i] == x {
198+
return true
199+
}
169200
}
170-
if b[0][i] == p && b[1][i] == p && b[2][i] == p {
201+
if board[0][0] == x && board[1][1] == x && board[2][2] == x {
171202
return true
172203
}
204+
return board[0][2] == x && board[1][1] == x && board[2][0] == x
173205
}
174-
if b[0][0] == p && b[1][1] == p && b[2][2] == p {
175-
return true
206+
if x != o && x-1 != o {
207+
return false
208+
}
209+
if win('X') && x-1 != o {
210+
return false
176211
}
177-
return b[0][2] == p && b[1][1] == p && b[2][0] == p
212+
return !(win('O') && x != o)
178213
}
179214
```
180215

181-
### **C++**
182-
183-
```cpp
184-
class Solution {
185-
public:
186-
bool validTicTacToe(vector<string>& board) {
187-
int x = 0, o = 0;
188-
for (int i = 0; i < 3; ++i) {
189-
for (int j = 0; j < 3; ++j) {
190-
if (board[i][j] == 'X') {
191-
++x;
192-
} else if (board[i][j] == 'O') {
193-
++o;
194-
}
216+
### **JavaScript**
217+
218+
```js
219+
/**
220+
* @param {string[]} board
221+
* @return {boolean}
222+
*/
223+
var validTicTacToe = function (board) {
224+
function count(x) {
225+
let cnt = 0;
226+
for (const row of board) {
227+
for (const c of row) {
228+
cnt += c == x;
195229
}
196230
}
197-
if (x != o && x - 1 != o) {
198-
return false;
199-
}
200-
if (win(board, 'X') && x - 1 != o) {
201-
return false;
202-
}
203-
return !(win(board, 'O') && x != o);
231+
return cnt;
204232
}
205-
206-
bool win(vector<string>& b, char p) {
207-
for (int i = 0; i < 3; ++i) {
208-
if (b[i][0] == p && b[i][1] == p && b[i][2] == p) {
233+
function win(x) {
234+
for (let i = 0; i < 3; ++i) {
235+
if (board[i][0] == x && board[i][1] == x && board[i][2] == x) {
209236
return true;
210237
}
211-
if (b[0][i] == p && b[1][i] == p && b[2][i] == p) {
238+
if (board[0][i] == x && board[1][i] == x && board[2][i] == x) {
212239
return true;
213240
}
214241
}
215-
if (b[0][0] == p && b[1][1] == p && b[2][2] == p) {
242+
if (board[0][0] == x && board[1][1] == x && board[2][2] == x) {
216243
return true;
217244
}
218-
return b[0][2] == p && b[1][1] == p && b[2][0] == p;
245+
return board[0][2] == x && board[1][1] == x && board[2][0] == x;
246+
}
247+
const [x, o] = [count('X'), count('O')];
248+
if (x != o && x - 1 != o) {
249+
return false;
250+
}
251+
if (win('X') && x - 1 != o) {
252+
return false;
219253
}
254+
return !(win('O') && x != o);
220255
};
221256
```
222257

0 commit comments

Comments
 (0)