题目描述
设计一个算法,判断玩家是否赢了井字游戏。输入是一个 N x N 的数组棋盘,由字符" ",“X"和"O"组成,其中字符” "代表一个空位。
以下是井字游戏的规则:
玩家轮流将字符放入空位(" “)中。
第一个玩家总是放字符"O”,且第二个玩家总是放字符"X"。
"X"和"O"只允许放置在空位中,不允许对已放有字符的位置进行填充。
当有N个相同(且非空)的字符填充任何行、列或对角线时,游戏结束,对应该字符的玩家获胜。
当所有位置非空时,也算为游戏结束。
如果游戏结束,玩家不允许再放置字符。
如果游戏存在获胜者,就返回该游戏的获胜者使用的字符(“X"或"O”);如果游戏以平局结束,则返回 “Draw”;如果仍会有行动(游戏未结束),则返回 “Pending”。
示例 1:
- 输入: board = [“O X”," XO",“X O”]
- 输出: “X”
示例 2:
- 输入: board = [“OOX”,“XXO”,“OXO”]
- 输出: “Draw”
- 解释: 没有玩家获胜且不存在空位
示例 3:
- 输入: board = [“OOX”,“XXO”,"OX "]
- 输出: “Pending”
- 解释: 没有玩家获胜且仍存在空位
提示:
- 1 <= board.length == board[i].length <= 100
- 输入一定遵循井字棋规则
解题思路与代码
这道题,我做的时候,属实是高看了它一眼,竟然想要用动态规划的法子一次性去检查横竖斜三个方向去做这道题。果不其然在三小时后遗憾败北。
再一看,这道题尽然无比简单。只需要分别去检查横,竖,斜,就简简单单做出来了。写完代码,加检查可能都不到10分钟。
哎,遗憾遗憾,紧接着,让我来讲讲这道题是怎么做的吧。
方法一 分别检查横,竖,斜三个方向,是否有获胜条件
-
我们首先需要设置9个int变量。去记录每种棋子横(两种)竖(两种)斜(四种)的个数,还有空位的个数。
-
用一个双层for循环去遍历这个棋盘,如果找到了符合条件的获胜条件,就直接返回。
具体代码如下:
class Solution {
public:
string tictactoe(vector<string>& board) {
int size = board.size(); // 棋盘的大小
int nullCount = 0; // 空的位置
int rowO, colO, diagO = 0, antiDiagO = 0;
int rowX, colX, diagX = 0, antiDiagX = 0;
for (int i = 0; i < size; ++i) {
rowO = colO = rowX = colX = 0;
for (int j = 0; j < size; ++j) {
if (board[i][j] == 'O') rowO++;
else if (board[i][j] == 'X') rowX++;
else nullCount++;
if (board[j][i] == 'O') colO++;
else if (board[j][i] == 'X') colX++;
}
if (board[i][i] == 'O') diagO++;
else if (board[i][i] == 'X') diagX++;
if (board[i][size - 1 - i] == 'O') antiDiagO++;
else if (board[i][size - 1 - i] == 'X') antiDiagX++;
if (rowO == size || colO == size || diagO == size || antiDiagO == size) return "O";
if (rowX == size || colX == size || diagX == size || antiDiagX == size) return "X";
}
return nullCount > 0 ? "Pending" : "Draw";
}
};
复杂度分析
-
时间复杂度:O(n^2),因为我们遍历了整个棋盘,需要对每个元素进行检查。
-
空间复杂度:O(1),我们没有使用额外的数据结构来存储信息,只使用了几个额外的变量来记录行、列和对角线的状态。
总结
最近做八皇后这样的困难题做多了。题一上来可能就有点往复杂的思路上去靠,结果反而得不偿失。
做题还是先想想有没有简单的做法,没有再去往各种算法的思想上去靠。
这道题其实就是朴实无华的一道棋盘问题。
最后的最后,如果你觉得我的这篇文章写的不错的话,请给我一个赞与收藏,关注我,我会继续给大家带来更多更优质的干货内容
。