Design a Tic-tac-toe game that is played between two players on a n x n grid.

You may assume the following rules:

  1. A move is guaranteed to be valid and is placed on an empty block.
  2. Once a winning condition is reached, no more moves is allowed.
  3. A player who succeeds in placing n of their marks in a horizontal, vertical, or diagonal row wins the game.

Example:

Given n = 3, assume that player 1 is "X" and player 2 is "O" in the board.

TicTacToe toe = new TicTacToe(3);

toe.move(0, 0, 1); -> Returns 0 (no one wins)
|X| | |
| | | | // Player 1 makes a move at (0, 0).
| | | | toe.move(0, 2, 2); -> Returns 0 (no one wins)
|X| |O|
| | | | // Player 2 makes a move at (0, 2).
| | | | toe.move(2, 2, 1); -> Returns 0 (no one wins)
|X| |O|
| | | | // Player 1 makes a move at (2, 2).
| | |X| toe.move(1, 1, 2); -> Returns 0 (no one wins)
|X| |O|
| |O| | // Player 2 makes a move at (1, 1).
| | |X| toe.move(2, 0, 1); -> Returns 0 (no one wins)
|X| |O|
| |O| | // Player 1 makes a move at (2, 0).
|X| |X| toe.move(1, 0, 2); -> Returns 0 (no one wins)
|X| |O|
|O|O| | // Player 2 makes a move at (1, 0).
|X| |X| toe.move(2, 1, 1); -> Returns 1 (player 1 wins)
|X| |O|
|O|O| | // Player 1 makes a move at (2, 1).
|X|X|X|

Follow up:
Could you do better than O(n2) per move()

Hint:

Could you trade extra space such that move() operation can be done in O(1)?
You need two arrays: int rows[n], int cols[n], plus two variables: diagonal, anti_diagonal.

CareerCup上的原题,请参见我之前的博客17.2 Tic Tac Toe。我们首先来O(n2)的解法,这种方法的思路很straightforward,就是建立一个nxn大小的board,其中0表示该位置没有棋子,1表示玩家1放的子,2表示玩家2。那么棋盘上每增加一个子,我们都扫描当前行列,对角线,和逆对角线,看看是否有三子相连的情况,有的话则返回对应的玩家,没有则返回0,参见代码如下:

解法一:

class TicTacToe {
public:
/** Initialize your data structure here. */
TicTacToe(int n) {
board.resize(n, vector<int>(n, ));
} int move(int row, int col, int player) {
board[row][col] = player;
int i = , j = , n = board.size();
for (j = ; j < n; ++j) {
if (board[row][j] != board[row][j - ]) break;
}
if (j == n) return player;
for (i = ; i < n; ++i) {
if (board[i][col] != board[i - ][col]) break;
}
if (i == n) return player;
if (row == col) {
for (i = ; i < n; ++i) {
if (board[i][i] != board[i - ][i - ]) break;
}
if (i == n) return player;
}
if (row + col == n - ) {
for (i = ; i < n; ++i) {
if (board[n - i - ][i] != board[n - i][i - ]) break;
}
if (i == n) return player;
}
return ;
} private:
vector<vector<int>> board;
};

Follow up中让我们用更高效的方法,那么根据提示中的,我们建立一个大小为n的一维数组rows和cols,还有变量对角线diag和逆对角线rev_diag,这种方法的思路是,如果玩家1在第一行某一列放了一个子,那么rows[0]自增1,如果玩家2在第一行某一列放了一个子,则rows[0]自减1,那么只有当rows[0]等于n或者-n的时候,表示第一行的子都是一个玩家放的,则游戏结束返回该玩家即可,其他各行各列,对角线和逆对角线都是这种思路,参见代码如下:

解法二:

class TicTacToe {
public:
/** Initialize your data structure here. */
TicTacToe(int n): rows(n), cols(n), N(n), diag(), rev_diag() {} int move(int row, int col, int player) {
int add = player == ? : -;
rows[row] += add;
cols[col] += add;
diag += (row == col ? add : );
rev_diag += (row == N - col - ? add : );
return (abs(rows[row]) == N || abs(cols[col]) == N || abs(diag) == N || abs(rev_diag) == N) ? player : ;
} private:
vector<int> rows, cols;
int diag, rev_diag, N;
};

参考资料:

https://leetcode.com/problems/design-tic-tac-toe/

https://discuss.leetcode.com/topic/44548/java-o-1-solution-easy-to-understand

https://discuss.leetcode.com/topic/44605/c-time-o-1-space-o-n-short-simple-solution

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Design Tic-Tac-Toe 设计井字棋游戏的更多相关文章

  1. [LeetCode] 348. Design Tic-Tac-Toe 设计井字棋游戏

    Design a Tic-tac-toe game that is played between two players on a n x n grid. You may assume the fol ...

  2. [Swift]LeetCode348. 设计井字棋游戏 $ Design Tic-Tac-Toe

    Design a Tic-tac-toe game that is played between two players on a n x n grid. You may assume the fol ...

  3. [CareerCup] 17.2 Tic Tac Toe 井字棋游戏

    17.2 Design an algorithm to figure out if someone has won a game oftic-tac-toe. 这道题让我们判断玩家是否能赢井字棋游戏, ...

  4. [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 r ...

  5. 井字棋游戏升级版 - TopTicTacToe项目 简介

    一.游戏简介 井字棋是一款世界闻名的游戏,不用我说,你一定知道它的游戏规则. 这款游戏简单易学,玩起来很有意思,不过已经证明出这款游戏如果两个玩家都足够聪明的话, 是很容易无法分出胜负的,即我们得到的 ...

  6. JavaFX 井字棋游戏

    利用JavaFX设计一个井字棋游戏,其中包括了能够与玩家对战的AI.AI的实现相比五子棋来说要简单得多,可以保证AI在后手情况下绝对不会输,具体实现如下: /* * To change this li ...

  7. C++井字棋游戏,DOS界面版

    据说有一个能保证不败的算法.明天看看先再写个PVC版的. 正题.今天无聊写了个井字棋游戏,顺便逐渐让自己习惯良好的代码风格,放上来给新手学习学习. jzq2.cpp /* N字棋游戏PVP版,DOS版 ...

  8. Java井字棋游戏

    试着写了一个井字棋游戏,希望各位能给予一些宝贵的建议. 一.棋盘类 package 井字棋游戏; public class ChessBoard { private int number; Perso ...

  9. [C++] 井字棋游戏源码

    TicTac.h #define EX 1 //该点左鼠标 #define OH 2 //该点右鼠标 class CMyApp : public CWinApp { public: virtual B ...

随机推荐

  1. Oracle数据加载之sqlldr工具的介绍

    环境: 服务端:RHEL6.4 + Oracle 11.2.0.4 客户端:WIN10 + Oracle 11.2.0.1 client 目录: sqlldr语法 sqlldr实验准备 sqlldr常 ...

  2. ASP.NET Core 中文文档 第四章 MVC(2.2)模型验证

    原文:Model Validation 作者:Rachel Appel 翻译:娄宇(Lyrics) 校对:孟帅洋(书缘) 在这篇文章中: 章节: 介绍模型验证 验证 Attribute 模型状态 处理 ...

  3. [原创]django+ldap+memcache实现单点登录+统一认证

    前言 由于公司内部的系统越来越多,为了方便用户使用,通过django进行了单点登录和统一认证的尝试,目前实现了django项目的单点登录和非django项目的统一认证,中间波折挺多,涉及的技术包括dj ...

  4. IBatisNet -- 保护你的配置文件及映射文件信息

    通常情况下我们在使用IBatisNet的时候,配置文件和映射文件都是暴露在外的,如果能进入到服务器,那么你的程序的操作数据库的SQL语句,数据库连接字符串等信息都将很轻松的被看到,这样是很危险的.然而 ...

  5. [转] 评 WOW技能天赋设计

    本文转至:http://bbs.chinaunix.net/thread-1692302-8-1.html(只作转载, 不代表本站和博主同意文中观点或证实文中信息)再比如,传说中的面向对象本该大显神威 ...

  6. Stream

    Stream的好处 1.Stream AP的引入弥补了JAVA函数式编程的缺陷.2.Stream相比集合类占用内存更小:集合类里的元素是存储在内存里的,Stream里的元素是在访问的时候才被计算出来. ...

  7. 几句话就能让你理解:this、闭包、原型链

    以下是个人对这三个老大难的总结(最近一直在学习原生JS,翻了不少书,不少文档,虽然还是新手,但我会继续坚持走我自己的路) 原型链 所有对象都是基于Object.prototype,Object.pro ...

  8. JavaScript学习笔记1之基础知识点

    一.什么是JavaScrip JavaScript是一种动态类型.弱类型.基于原型的客户端脚本语言.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,在HTML网页 ...

  9. 纯js实现10分钟倒计时

    一个简单实现倒计时的小栗子~ 效果图:简陋的不能再简陋了,捂脸 代码: <!DOCTYPE HTML> <html> <head> <title> 倒计 ...

  10. [问题]apparmor 问题导致mysql切换datadir目录失败

    问题: 在mysql切换datadir后,mysql服务无法启动.出现错误说plugin表无法读取,需要用mysql_upgrade创建.但是其实不是这个问题. 原因: apparmor 会限制程序对 ...