• 算法刷题打卡第34天:有效的井字游戏


    有效的井字游戏

    难度:中等

    给你一个字符串数组 b o a r d board board 表示井字游戏的棋盘。当且仅当在井字游戏过程中,棋盘有可能达到 b o a r d board board 所显示的状态时,才返回 t r u e true true

    井字游戏的棋盘是一个 3 x 3 数组,由字符 ' ''X''O' 组成。字符 ' ' 代表一个空位。

    以下是井字游戏的规则:

    • 玩家轮流将字符放入空位(' ')中。
    • 玩家 1 总是放字符 'X' ,而玩家 2 总是放字符 'O'
    • 'X''O' 只允许放置在空位中,不允许对已放有字符的位置进行填充。
    • 当有 3 个相同(且非空)的字符填充任何行、列或对角线时,游戏结束。
    • 当所有位置非空时,也算为游戏结束。
    • 如果游戏结束,玩家不允许再放置字符。

    示例 1:

    在这里插入图片描述

    输入:board = ["O  ","   ","   "]
    输出:false
    解释:玩家 1 总是放字符 "X" 。
    
    • 1
    • 2
    • 3

    示例 2:

    在这里插入图片描述

    输入:board = ["XOX"," X ","   "]
    输出:false
    解释:玩家应该轮流放字符。
    
    • 1
    • 2
    • 3

    示例 3:

    在这里插入图片描述

    输入:board = ["XOX","O O","XOX"]
    输出:true
    
    • 1
    • 2

    分类讨论

    思路:
    题目要求判断当前游戏板是否生效,我们思考游戏板生效的规则:

    • 玩家轮流将字符放入空位 "   " \texttt{" "} " " 中。第一个玩家总是放字符 "X" \texttt{"X"} "X",且第二个玩家总是放字符 "O" \texttt{"O"} "O"。因为第一个玩家总是先手,这就要求游戏板中字符 "X" \texttt{"X"} "X" 的数量一定是大于等于字符 "O" \texttt{"O"} "O" 的数量。
    • "X" \texttt{"X"} "X" "O" \texttt{"O"} "O" 只允许放置在空位中,不允许对已放有字符的位置进行填充。
    • 当有 3 3 3 个相同(且非空)的字符填充任何行、列或对角线时,游戏结束。当所有位置非空时,也算为游戏结束。如果游戏结束,玩家不允许再放置字符,不可能能出现二者同时获胜的情况,因此游戏板上不可能同时出现 3 3 3 "X" \texttt{"X"} "X" 在一行和 3 3 3 "O" \texttt{"O"} "O" 在另一行。
    • 获胜的玩家一定是在自己放棋后赢得比赛,赢得比赛后,立马停止放置字符。
      • 如果第一个玩家获胜,由于第一个玩家是先手,则次数游戏板中 "X" \texttt{"X"} "X" 的数量比 "O" \texttt{"O"} "O" 的数量多 1 1 1
      • 如果第二个玩家获胜,则 "X" \texttt{"X"} "X" 的数量与 "O" \texttt{"O"} "O" 的数量相同。

    以上条件包含了游戏板生效的全部情况,可以通过反证法验证上面分类条件的正确性。在合法的游戏板,只能有 3 3 3 种结果合法,要么没有任何玩家赢,要么玩家一赢,要么玩家二赢。我们可以通过检查两种棋的数量关系即可验证是否有效,同时我们要检测是否存在两个玩家同时赢这种非法情况。

    算法实现细节如下:

    • 首先统计游戏板上 "X" \texttt{"X"} "X" "O" \texttt{"O"} "O" 的数量并记录在 xCount \textit{xCount} xCount oCount \textit{oCount} oCount 中,如果不满足 xCount ≥ oCount \textit{xCount} \ge \textit{oCount} xCountoCount,则此时为非法,直接返回 false \texttt{false} false
    • 然后我们检查是否有玩家是否获胜,我们检查在棋盘的 3 3 3 行, 3 3 3 列和 2 2 2 条对角线上是否有该玩家的连续 3 3 3 枚棋子。我们首先检测玩家一是否获胜,如果玩家一获胜,则检查 xCount \textit{xCount} xCount 是否等于 oCount + 1 \textit{oCount} + 1 oCount+1;我们继续检测玩家二是否获胜,如果玩家二获胜,则检查 xCount \textit{xCount} xCount 是否等于 oCount \textit{oCount} oCount
    • 对于特殊情况如果两个玩家都获胜,是否可以检测出该非法情况?如果同时满足两个玩家都获胜,则 "X" \texttt{"X"} "X" "O" \texttt{"O"} "O" 数量的合法的组合可能为 ( 3 , 3 ) , ( 4 , 3 ) , ( 4 , 4 ) , ( 5 , 4 ) (3,3),(4,3),(4,4),(5,4) (3,3),(4,3),(4,4),(5,4),对于 ( 3 , 3 ) , ( 4 , 4 ) (3,3),(4,4) (3,3),(4,4) 不满足玩家一获胜的检测条件,对于 ( 4 , 3 ) , ( 5 , 4 ) (4,3),(5,4) (4,3),(5,4) 满足玩家一获胜的检测条件但不满足玩家二的获胜条件。

    时间复杂度: O ( C ) O(C) O(C),由于此题给定的棋盘大小为常数 C = 9 C=9 C=9,因此时间复杂度为常数。
    空间复杂度: O ( 1 ) O(1) O(1)

    class Solution:
        def win(self, char, board):
            return any(board[0][i] == char and board[1][i] == char and board[2][i] == char or
                       board[i][0] == char and board[i][1] == char and board[i][2] == char for i in range(3)) or \
                       board[0][0] == char and board[1][1] == char and board[2][2] == char or \
                       board[2][0] == char and board[1][1] == char and board[0][2] == char
        def validTicTacToe(self, board: List[str]) -> bool:
            ocount = sum(row.count("O") for row in board)
            xcount = sum(row.count("X") for row in board)
            return not (xcount - ocount not in [0, 1] or
                       xcount - ocount != 0 and self.win('O', board) or
                       xcount - ocount != 1 and self.win('X', board))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    来源:力扣(LeetCode)
    链接:https://leetcode.cn/problems/valid-tic-tac-toe-state

  • 相关阅读:
    毕设-原创医疗预约挂号平台分享
    Lyx使用bib插入参考文献
    MySQL编程基础与变量
    不要高估迷信自己的毅力:交钱后坚持培训的比例不到1%
    flink1.15源码笔记
    [UNR #6]稳健型选手
    ARM的七种工作模式与异常
    基于轻量级yolov5的无人机航拍场景下的森林火情检测识别系统
    pat_basic_1013 数素数
    驱动开发:内核LDE64引擎计算汇编长度
  • 原文地址:https://blog.csdn.net/weixin_45616285/article/details/128162679