Leetcode 第 794 题(Valid Tic-Tac-Toe State)
A Tic-Tac-Toe board is given as a string array
board
. Return True if and only if it is possible to reach this board position during the course of a valid tic-tac-toe game.The
board
is a 3 x 3 array, and consists of characters" "
,"X"
, and"O"
. The ” ” character represents an empty square.Here are the rules of Tic-Tac-Toe:
- Players take turns placing characters into empty squares (” “).
- The first player always places “X” characters, while the second player always places “O” characters.
- “X” and “O” characters are always placed into empty squares, never filled ones.
- The game ends when there are 3 of the same (non-empty) character filling any row, column, or diagonal.
- The game also ends if all squares are non-empty.
- No more moves can be played if the game is over.
Example 1:
Input: board = ["O ", " ", " "]
Output: false
Explanation: The first player always plays "X".
Example 2:
Input: board = ["XOX", " X ", " "]
Output: false
Explanation: Players take turns making moves.
Example 3:
Input: board = ["XXX", " ", "OOO"]
Output: false
Example 4:
Input: board = ["XOX", "O O", "XOX"]
Output: true
这道题的难度是 Medium。其实写起来难度并不大,但是一次就写好还是挺难的。主要是各种情况都要考虑到,而且还有几种特殊情况。
我的解法是先统计 “X” 和 “O” 的数量。如果 X > O + 1 或者 X < O 那都肯定是不能出现的状态。
之后统计 “X” 和 “O” 各出现了几次获胜状态。当 X 比 O 多一个子时才能出现 X 获胜的情况。X 和 O 子相同时只能出现 O 获胜的情况。
计算子数的函数如下:
/**
* @brief count 计算 X 和 O 各有多少个子
* @param board
* @param x 返回 X 的子数
* @param o 返回 O 的子数
*/
void count (vector<string>& board, int &x, int &o)
{
x = 0; o = 0;
for(int i = 0; i < 3; i ++)
{
for(int j = 0; j < 3; j++)
{
char t = board[i][j];
if(t == 'X') x++;
if(t == 'O') o++;
}
}
}
计算出现了多少种获胜情况的代码如下:
void cross(vector<string>& board, int &x, int &o)
{
x = 0; o = 0;
char buf[4];
buf[3] = 0;
buf[0] = board.at(0).at(0);
buf[1] = board.at(1).at(1);
buf[2] = board.at(2).at(2);
if(strcmp(buf, "XXX") == 0) x++;
if(strcmp(buf, "OOO") == 0) o++;
buf[0] = board.at(0).at(2);
buf[1] = board.at(1).at(1);
buf[2] = board.at(2).at(0);
if(strcmp(buf, "XXX") == 0) x++;
if(strcmp(buf, "OOO") == 0) o++;
}
void col(vector<string>& board, int &x, int &o)
{
x = 0; o = 0;
for(int i = 0; i < 3; i ++)
{
char buf[4];
buf[3] = 0;
buf[0] = board.at(0).at(i);
buf[1] = board.at(1).at(i);
buf[2] = board.at(2).at(i);
if(strcmp(buf, "XXX") == 0) x++;
if(strcmp(buf, "OOO") == 0) o++;
}
}
void row(vector<string>& board, int &x, int &o)
{
x = 0; o = 0;
for(int i = 0; i < 3; i ++)
{
if(board.at(i) == "XXX") x++;
if(board.at(i) == "OOO") o++;
}
}
/**
* @brief win
* @param board
* @param x 返回 X 有多少种获胜条件
* @param o 返回 O 有多少种获胜条件
*/
void win(vector<string>& board, int &x, int &o)
{
x = 0;
o = 0;
int x_count, o_count;
row(board, x_count, o_count);
x += x_count;
o += o_count;
col(board, x_count, o_count);
x += x_count;
o += o_count;
cross(board, x_count, o_count);
x += x_count;
o += o_count;
}
把这几个判断合到一起就可以了。
bool validTicTacToe(vector<string>& board)
{
int x_stone, o_stone;
count(board, x_stone, o_stone);
if(o_stone > x_stone) return false;
if(x_stone > o_stone + 1) return false;
int x_count = 0, o_count = 0;
win(board, x_count, o_count);
if(x_count > 0 && x_stone == o_stone) return false;
if(o_count > 0 && x_stone > o_stone) return false;
return true;
}
至此这个代码就完成了。其中计算出现了多少次获胜条件的代码写的比较 Naive。还可以优化一下,大家可以试着改一改。