【思维题】B044_LC_有效的井字游戏(讨论X和O的个数)

一、Problem

用字符串数组作为井字游戏的游戏板 board。当且仅当在井字游戏过程中,玩家有可能将字符放置成游戏板所显示的状态时,才返回 true。

该游戏板是一个 3 x 3 数组,由字符 " ",“X” 和 “O” 组成。字符 " " 代表一个空位。

以下是井字游戏的规则:

  • 玩家轮流将字符放入空位(" ")中。
  • 第一个玩家总是放字符 “X”,且第二个玩家总是放字符 “O”。
  • “X” 和 “O” 只允许放置在空位中,不允许对已放有字符的位置进行填充。
  • 当有 3 个相同(且非空)的字符填充任何行、列或对角线时,游戏结束。
  • 当所有位置非空时,也算为游戏结束。
  • 如果游戏结束,玩家不允许再放置字符。
输入: board = ["XOX", " X ", "   "]
输出: false
解释: 玩家应该是轮流放置的

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

说明:
游戏板 board 是长度为 3 的字符串数组,其中每个字符串 board[i] 的长度为 3
board[i][j] 是集合 {" ", “X”, “O”} 中的一个字符

二、Solution

方法一:分类讨论

思考

没啥规律,只能检查各种情况…

  • O 的数量 ⩽ \leqslant X 的数量,且 X-O ⩽ \leqslant 1;剩下的工作就是讨论仅有的两种情况:
    • X ≥ O 的前提下,如果 X 和 O 一样多,但 X 赢了,不可能有这种情况啊,因为 X 都赢了,O 为什么还有;[“XXX”, " ", “OOO”]
    • 如果 X - O = 1,但 O 赢了,不存在该情况;因为 O 是后手,在放 O 之前,O 一定严格小于 X 的个数
class Solution {
public:
    bool chk(vector<string>& g, char c) {
        for (int i=0; i<3; i++) {
            if (g[i][0]==g[i][1] && g[i][1]==g[i][2] && g[i][2]==c) return true;
            if (g[0][i]==g[1][i] && g[1][i]==g[2][i] && g[2][i]==c) return true;
        }
        if (g[0][0]==g[1][1] && g[1][1]==g[2][2] && g[2][2]==c) return true;
        if (g[0][2]==g[1][1] && g[1][1]==g[2][2] && g[2][2]==c) return true;
        return false;
    }
    bool validTicTacToe(vector<string>& g) {
        int X=0, O=0, n=3;
        for (int i=0; i<n; i++)
        for (int j=0; j<n; j++) {
            if (g[i][j] == 'O') O++;
            else if (g[i][j] == 'X') X++;
        }
        // x 先手还比后手的o少或者x多放了2~n个,还合法吗
        if (O > X || X-O > 1) return false;
        // X-O == 0 or X-O == 1
            // X>=O的前提下,如果X和O一样多,但X赢了,不可能有这种情况啊,X都赢了,O为什么还有,["XXX", "   ", "OOO"]
        if (O == X && chk(g, 'X')) return false;
            // 如果X比O多一个,但O赢了,也不可能
        if (X-O==1 && chk(g, 'O')) return false;
        return true;
    }
};

复杂度分析

  • 时间复杂度: O ( 1 ) O(1) O(1)
  • 空间复杂度: O ( 1 ) O(1) O(1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值