leetcode 1275. 找出井字棋的獲勝者(待研究)

【題目】1275. 找出井字棋的獲勝者

A 和 B 在一個 3 x 3 的網格上玩井字棋。
井字棋遊戲的規則如下:

  • 玩家輪流將棋子放在空方格 (" ") 上。
  • 第一個玩家 A 總是用 “X” 作爲棋子,而第二個玩家 B 總是用 “O” 作爲棋子。
  • “X” 和 “O” 只能放在空方格中,而不能放在已經被佔用的方格上。
  • 只要有 3 個相同的(非空)棋子排成一條直線(行、列、對角線)時,遊戲結束。
  • 如果所有方塊都放滿棋子(不爲空),遊戲也會結束。
  • 遊戲結束後,棋子無法再進行任何移動。

給你一個數組 moves,其中每個元素是大小爲 2 的另一個數組(元素分別對應網格的行和列),它按照 A 和 B 的行動順序(先 A 後 B)記錄了兩人各自的棋子位置。
如果遊戲存在獲勝者(A 或 B),就返回該遊戲的獲勝者;如果遊戲以平局結束,則返回 “Draw”;如果仍會有行動(遊戲未結束),則返回 “Pending”。
你可以假設 moves 都 有效(遵循井字棋規則),網格最初是空的,A 將先行動。

示例 1:

輸入:moves = [[0,0],[2,0],[1,1],[2,1],[2,2]]
輸出:"A"
解釋:"A" 獲勝,他總是先走。
"X  "    "X  "    "X  "    "X  "    "X  "
"   " -> "   " -> " X " -> " X " -> " X "
"   "    "O  "    "O  "    "OO "    "OOX"

示例 2:

輸入:moves = [[0,0],[1,1],[0,1],[0,2],[1,0],[2,0]]
輸出:"B"
解釋:"B" 獲勝。
"X  "    "X  "    "XX "    "XXO"    "XXO"    "XXO"
"   " -> " O " -> " O " -> " O " -> "XO " -> "XO " 
"   "    "   "    "   "    "   "    "   "    "O  "

示例 3:

輸入:moves = [[0,0],[1,1],[2,0],[1,0],[1,2],[2,1],[0,1],[0,2],[2,2]]
輸出:"Draw"
輸出:由於沒有辦法再行動,遊戲以平局結束。
"XXO"
"OOX"
"XOX"

示例 4:

輸入:moves = [[0,0],[1,1]]
輸出:"Pending"
解釋:遊戲還沒有結束。
"X  "
" O "
"   "

提示:
1 <= moves.length <= 9
moves[i].length == 2
0 <= moves[i][j] <= 2
moves 裏沒有重複的元素。
moves 遵循井字棋的規則。

【解題思路1】模擬

public String tictactoe(int[][] moves) {
	int m = moves.length;
	// 用數組記錄0-2行、0-2列、正對角線、副對角線是否已滿3個棋子
	// count[0-2]對應0-2行、count[3-5]對應0-2列、count[6]對應正對角線、count[7]對應副對角線
	int[] count = new int[8];
	// 思路第2步已解釋爲何只需考慮最後一個落棋的人
	// 倒序統計此人走棋情況
	for(int i = m - 1; i >= 0; i -= 2) {
		// 此棋對行的影響
		count[moves[i][0]]++;
		// 此棋對列的影響
		count[moves[i][1] + 3]++;	
		// 此棋對正對角線的影響
		if(moves[i][0] == moves[i][1])
			count[6]++;
		// 此棋對副對角線的影響 (
		// 此處爲3x3的情況,其餘大小的棋盤可以類推
		if(moves[i][0] + moves[i][1] == 2)
			count[7]++;
		// 滿3個棋子則勝利
		if(count[moves[i][0]] == 3 || count[moves[i][1] + 3] == 3 || 
				count[6] == 3 || count[7] == 3) 
			// A先B後 則總長度爲偶時 最後爲B 反之爲A
			return m % 2 == 0 ? "B" : "A";	
		}
	// 未勝時,棋盤未下滿則繼續
	if(moves.length < 9)
		return "Pending";
	// 未勝時,棋盤下滿則平局結束
	return "Draw";
}

【解題思路2】位運算

public String tictactoe(int[][] moves) {
    // a, b record the moving results of A, B
    int a = 0, b = 0, len = moves.length;
    // ac records all cases of winning
    int[] ac = {7, 56, 448, 73, 146, 292, 273, 84};
    for(int i = 0; i < len; i ++){
        // if i is add
        if((i & 1) == 1){
            // record the step result
            b ^= 1 << (3 * moves[i][0] + moves[i][1]);
        }
        else {
            a ^= 1 << (3 * moves[i][0] + moves[i][1]);
        }
    }
    for(int i : ac){
        // if the moving result contains the winning case in record, then win
        if((a & i) == i){
            return "A";
        }
        if((b & i) == i){
            return "B";
        }
    }
    // or judge the result by the amount of steps
    return len == 9 ? "Draw" : "Pending";
}

【解題思路3】分開存分開判斷

class Solution {
    public String tictactoe(int[][] moves) {
        int [][] A = new int[3][3];
        int [][] B = new int[3][3];
        for (int i = 0; i < moves.length; i++) {
            if (i%2 == 0){
                A[moves[i][0]][moves[i][1]] = 1;
            }else {
                B[moves[i][0]][moves[i][1]] = 2;
            }
        }
        for (int i = 0; i < 3; i++) {
            if(A[i][0] + A[i][1] + A[i][2] == 3)
                return "A";
        }
        for (int i = 0; i < 3; i++) {
            if(A[0][i] + A[1][i] + A[2][i] == 3)
                return "A";
        }
        if(A[0][0] + A[1][1] + A[2][2] == 3 || A[2][0] + A[1][1] + A[0][2] == 3)
            return "A";
        for (int i = 0; i < 3; i++) {
            if(B[i][0] + B[i][1] + B[i][2] == 6)
                return "B";
        }
        for (int i = 0; i < 3; i++) {
            if(B[0][i] + B[1][i] + B[2][i] == 6)
                return "B";
        }
        if(B[0][0] + B[1][1] + B[2][2] == 6 || B[2][0] + B[1][1] + B[0][2] == 6)
            return "B";
        if (moves.length == 9)
            return "Draw";
        return "Pending";
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章