LeetCode 794 - Valid Tic-Tac-Toe State


https://leetcode.com/problems/valid-tic-tac-toe-state/description/
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
Note:
  • board is a length-3 array of strings, where each string board[i] has length 3.
  • Each board[i][j] is a character in the set {" ", "X", "O"}.
http://www.cnblogs.com/grandyang/p/9223105.html
这道题又是关于井字棋游戏的,之前也有一道类似的题Design Tic-Tac-Toe,不过那道题是模拟游戏进行的,而这道题是让我们验证当前井字棋的游戏状态是否正确。这题的例子给的比较好,cover了很多种情况:
情况一:
0 _ _
_ _ _
_ _ _
这是不正确的状态,因为先走的使用X,所以只出现一个O,是不对的。
情况二:
X O X
_ X _
_ _ _
这个也是不正确的,因为两个player交替下棋,X最多只能比O多一个,这里多了两个,肯定是不对的。
情况三:
X X X
_ _ _ 
O O O
这个也是不正确的,因为一旦第一个玩家的X连成了三个,那么游戏马上结束了,不会有另外一个O出现。
情况四:
X O X
O _ O
X O X
这个状态没什么问题,是可以出现的状态。
好,那么根据给的这些例子,我们可以分析一下规律,根据例子1和例子2我们得出下棋顺序是有规律的,必须是先X后O,不能破坏这个顺序,那么我们可以使用一个turns变量,当是X时,turns自增1,反之若是O,则turns自减1,那么最终turns一定是0或者1,其他任何值都是错误的,比如例子1中,turns就是-1,例子2中,turns是2,都是不对的。根据例子3,我们得出结论,只能有一个玩家获胜,那么我们可以用两个变量xwin和owin,来记录两个玩家的获胜状态,由于井字棋的制胜规则是横竖斜任意一个方向有三个连续的就算赢,那么我们分别在各个方向查找3个连续的X,有的话xwin赋值为true,还要查找3个连续的O,有的话owin赋值为true,例子3中xwin和owin同时为true了,是错误的。还有一种情况,例子中没有cover到的是:
情况五:
X X X
O O _
O _ _
我们看到虽然只有xwin为true,但是这种状态还是错误的,因为一旦第三个X放下后,游戏立即结束,不会有第三个O放下,这么检验这种情况呢?这是我们的turns变量就非常的重要了,当第三个O放下后,turns自减1,此时turns为0了,而正确的应该是当xwin为true的时候,第三个O不能放下,那么turns不减1,则还是1,这样就可以区分情况五了。当然,我们可以交换X和O的位置,即当owin为true时,turns一定要为0。现在我们已经覆盖了搜索的情况了
https://leetcode.com/problems/valid-tic-tac-toe-state/discuss/117580/Straightforward-Java-solution-with-explaination
When turns is 1, X moved. When turns is 0, O moved. rows stores the number of X or O in each row. cols stores the number of X or O in each column. diag stores the number of X or O in diagonal. antidiag stores the number of X or O in antidiagonal. When any of the value gets to 3, it means X wins. When any of the value gets to -3, it means O wins.
When X wins, O cannot move anymore, so turns must be 1. When O wins, X cannot move anymore, so turns must be 0. Finally, when we return, turns must be either 0 or 1, and X and O cannot win at same time.
    public boolean validTicTacToe(String[] board) {
        int turns = 0;
        boolean xwin = false; 
        boolean owin = false;
        int[] rows = new int[3];
        int[] cols = new int[3];
        int diag = 0;
        int antidiag = 0;
    
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (board[i].charAt(j) == 'X') {
                    turns++; rows[i]++; cols[j]++;
                    if (i == j) diag++;
                    if (i + j == 2) antidiag++;
                } else if (board[i].charAt(j) == 'O') {
                    turns--; rows[i]--; cols[j]--;
                    if (i == j) diag--;
                    if (i + j == 2) antidiag--;
                }
            }
        }
  
        xwin = rows[0] == 3 || rows[1] == 3 || rows[2] == 3 || 
               cols[0] == 3 || cols[1] == 3 || cols[2] == 3 || 
               diag == 3 || antidiag == 3;
        owin = rows[0] == -3 || rows[1] == -3 || rows[2] == -3 || 
               cols[0] == -3 || cols[1] == -3 || cols[2] == -3 || 
               diag == -3 || antidiag == -3;
        
        if (xwin && turns == 0 || owin && turns == 1) {
            return false;
        }
        return (turns == 0 || turns == 1) && (!xwin || !owin);
    }
https://zhuanlan.zhihu.com/p/34216982
首先我们要先熟悉下Tic-Tac-Toe三连棋游戏规则,就是两人轮流在九格方盘上画'X'或者'O',谁先把三个相同记号排成横线、直线、斜线,即游戏结束。

那么我们从游戏规则中来找处所有不合理的状态。

根据规则1和2,假设X的数目为countX, O的数目为countO,那么我们可以得到countX==countO,或者countX - countO == 1。

根据游戏结束后则不能再画O和X,那么当countX==count时,如果存在三个X排成横线、直线、斜线,那么即是不合理的,因为X先画,当三个X排成横线、直线、斜线时, 此时游戏结束,不能再画O,所以O的数目应该比X的数目少1。

当countX - countO == 1时,如果存在三个O排成横线、直线、斜线,那么是不合理的,因为当三个O排成横线、直线、斜线时,游戏结束,不能再画X,所以此时X的数目应该和O的数目相等。
public boolean validTicTacToe(String[] board) {
    char[][] boardChar = new char[3][3];
    for (int i = 0; i < board.length; i++) {
        boardChar[i] = board[i].toCharArray();
    }
    int countX = 0;
    int countO = 0;
    for (int i = 0; i < boardChar.length; i++) {
        for (int j = 0; j < boardChar[i].length; j++) {
            if (boardChar[i][j] == 'X') {
                countX++;
            } else if (boardChar[i][j] == 'O') {
                countO++;
            }
        }
    }
    if (countO > countX || countX - countO > 1) {
        return false;
    }
    if (countX - countO == 1) {
        if(!helper(boardChar, 'O')) {
            return false;
        }
    } else if (countX == countO) {
        if(!helper(boardChar, 'X')) {
            return false;
        }
    }

    return true;
}

private boolean helper(char[][] boardChar, char ch) {
    for (int i = 0; i < 3; i++) {
        if (boardChar[i][0] == ch && boardChar[i][0] == boardChar[i][1] && boardChar[i][1] == boardChar[i][2]) {
            return false;
        }
        if (boardChar[0][i] == ch && boardChar[0][i] == boardChar[1][i] && boardChar[1][i] == boardChar[2][i]) {
            return false;
        }
    }
    if (boardChar[0][0] == ch && boardChar[0][0] == boardChar[1][1] && boardChar[1][1] == boardChar[2][2]) {
        return false;
    }
    if (boardChar[0][2] == ch && boardChar[0][2] == boardChar[1][1] && boardChar[1][1] == boardChar[2][0]) {
        return false;
    }
    return true;
}
https://leetcode.com/problems/valid-tic-tac-toe-state/discuss/124024/Simple-Rule-Java-Solution
http://bookshadow.com/weblog/2018/03/04/leetcode-valid-tic-tac-toe-state/
def validTicTacToe(self, board): """ :type board: List[str] :rtype: bool """ nx = ''.join(board).count('X') no = ''.join(board).count('O') wx, wo = self.isWin(board, 'X'), self.isWin(board, 'O') if wx: return nx == no + 1 and not wo if wo: return nx == no return nx - 1 <= no <= nx def isWin(self, board, pc): if any(r == pc * 3 for r in board): return True if any(c == pc * 3 for c in zip(*board)): return True if board[0][0] == board[1][1] == board[2][2] == pc: return True if board[0][2] == board[1][1] == board[2][0] == pc: return True return False


https://www.geeksforgeeks.org/validity-of-a-given-tic-tac-toe-board-configuration/
Basically, to find the validity of an input grid, we can think of the conditions when an input grid is invalid. Let no. of “X”s be countX and no. of “O”s be countO. Since we know that the game starts with X, a given grid of Tic-Tac-Toe game would be definitely invalid if following two conditions meet
a) countX != countO AND
b) countX != countO + 1

Since “X” is always the first move, second condition is also required.
Now does it mean that all the remaining board positions are valid one? The answer is NO. Think of the cases when input grid is such that both X and O are making straight lines. This is also not valid position because the game ends when one player wins. So we need to check the following condition as well
c) If input grid shows that both the players are in winning situation, it’s an invalid position.
d) If input grid shows that the player with O has put a straight-line (i.e. is in win condition) and countX != countO, it’s an invalid position. The reason is that O plays his move only after X plays his move. Since X has started the game, O would win when both X and O has played equal no. of moves.
e) If input grid shows that X is in winning condition than xCount must be one greater that oCount.
Armed with above conditions i.e. a), b), c) and d), we can now easily formulate an algorithm/program to check the validity of a given Tic-Tac-Toe board position.
1)  countX == countO or countX == countO + 1
2)  If O is in win condition then check 
     a)     If X also wins, not valid
     b)     If xbox != obox , not valid
3)  If X is in win condition then check if xCount is
     one more than oCount or not  
Another way to find the validity of a given board is using ‘inverse method’ i.e. rule out all the possibilities when a given board is invalid.
// This matrix is used to find indexes to check all 
// possible wining triplets in board[0..8] 
    static int win[][] = {{0, 1, 2}, // Check first row. 
    {3, 4, 5}, // Check second Row 
    {6, 7, 8}, // Check third Row 
    {0, 3, 6}, // Check first column 
    {1, 4, 7}, // Check second Column 
    {2, 5, 8}, // Check third Column 
    {0, 4, 8}, // Check first Diagonal 
    {2, 4, 6}}; // Check second Diagonal 
  
// Returns true if character 'c' wins. c can be either 
// 'X' or 'O' 
    static boolean isCWin(char[] board, char c) {
        // Check all possible winning combinations 
        for (int i = 0; i < 8; i++) {
            if (board[win[i][0]] == c
                    && board[win[i][1]] == c
                    && board[win[i][2]] == c) {
                return true;
            }
        }
        return false;
    }
  
// Returns true if given board is valid, else returns false 
    static boolean isValid(char board[]) {
        // Count number of 'X' and 'O' in the given board 
        int xCount = 0, oCount = 0;
        for (int i = 0; i < 9; i++) {
            if (board[i] == 'X') {
                xCount++;
            }
            if (board[i] == 'O') {
                oCount++;
            }
        }
  
        // Board can be valid only if either xCount and oCount 
        // is same or xount is one more than oCount 
        if (xCount == oCount || xCount == oCount + 1) {
            // Check if 'O' is winner 
            if (isCWin(board, 'O')) {
                // Check if 'X' is also winner, then 
                // return false 
                if (isCWin(board, 'X')) {
                    return false;
                }
  
                // Else return true xCount and yCount are same 
                return (xCount == oCount);
            }
  
            // If 'X' wins, then count of X must be greater 
            if (isCWin(board, 'X') && xCount != oCount + 1) {
                return false;
            }
  
            // If 'O' is not winner, then return true 
            return true;
        }
        return false;
    }

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts