LeetCode 999. 車的可用捕獲量 - 方向數組思想
問題描述:
在一個 8 x 8 的棋盤上,有一個白色車(rook)。也可能有空方塊,白色的象(bishop)和黑色的卒(pawn)。它們分別以字符 “R”,“.”,“B” 和 “p” 給出。大寫字符表示白棋,小寫字符表示黑棋。
車按國際象棋中的規則移動:它選擇四個基本方向中的一個(北,東,西和南),然後朝那個方向移動,直到它選擇停止、到達棋盤的邊緣或移動到同一方格來捕獲該方格上顏色相反的卒。另外,車不能與其他友方(白色)象進入同一個方格。
求解問題:
返回車能夠在一次移動中捕獲到的卒的數量。
輸入:[[".",".",".",".",".",".",".","."],[".",".",".",“p”,".",".",".","."],[".",".",".",“R”,".",".",".",“p”],[".",".",".",".",".",".",".","."],
[".",".",".",".",".",".",".","."],[".",".",".",“p”,".",".",".","."],[".",".",".",".",".",".",".","."],[".",".",".",".",".",".",".","."]]
輸出:3
解釋:在本例中,車能夠捕獲所有的卒。
問題解決方案
1. 方案一(普通暴力法):
不優美的方式:
- 首先找到 “車” 這個棋的位置爲(2,3)
- 以車(2,3)的位置爲起點,分別向上下左右進行遍歷,判斷移動的位置是否爲 符合條件的卒。
public int numRookCaptures(char[][] board) {
int count = 0;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
// 查找車的位置
if (board[i][j] == 'R') {
//上
for (int l = j; l >= 0; l--) {
if (board[i][l] == 'B') {
break;
} else if (board[i][l] == 'p') {
count++;
break;
}
}
//下
for (int l = j; l < 8; l++) {
if (board[i][l] == 'B') {
break;
} else if (board[i][l] == 'p') {
count++;
break;
}
}
//左
for (int h = i; h >= 0; h--) {
if (board[h][j] == 'B') {
break;
} else if (board[h][j] == 'p') {
count++;
break;
}
}
//右
for (int h = i; h < 8; h++) {
if (board[h][j] == 'B') {
break;
} else if (board[h][j] == 'p') {
count++;
break;
}
}
}
}
}
return count;
}
這種方式寫出來的代碼會出現四個重複的for循環,十分不優美。
遂經過思考與參看資料,發現對於這一類的網格類的問題,可以通過方向數組來優化移動問題,具體講解見方式二。
2. 方式二(優化):
通過方向數組的思想,優化方案一中的上下左右四個暴力遍歷的方式。
方向數組
我們看面圖的案例,車的位置爲(2,3),車向上移1格之後的座標爲(1,3),其實(1,3)的由來爲:(2,3) +
同理,車向下移動一格之後的座標爲:(2,3) + = (3,3)
車向坐移動一格之後的座標爲:(2,3) + = (2,2)
車向下移動一格之後的座標爲:(2,3) + = (2,4)
我們可以定義兩個數組來模擬車移動的狀態:
// 定義方向數組
int[] dx = {-1, 1, 0, 0};
int[] dy = {0, 0, -1, 1};
優化之後的完整代碼:
package indi.pentiumcm.leetcode;
/**
* @projName: algorithm
* @packgeName: indi.pentiumcm.leetcode
* @className: Q11
* @author: pentiumCM
* @email: [email protected]
* @date: 2020/3/26 15:26
* @describe: LeetCode 999. 車的可用捕獲量
*/
public class Q11 {
public int numRookCapturesV2(char[][] board) {
int len = board.length;
// 定義喫到卒的個數
int count = 0;
// 定義方向數組
int[] dx = {-1, 1, 0, 0};
int[] dy = {0, 0, -1, 1};
// 查找車的位置
for (int i = 0; i < len; i++) {
for (int j = 0; j < len; j++) {
if (board[i][j] == 'R') {
// 上下左右四個方向分別移動
for (int k = 0; k < 4; k++) {
int x = i, y = j;
while (true) {
// 移動一步的增量:(-1, 0)-向上移動 1 格
x += dx[k];
y += dy[k];
// 移動超出棋盤
if (x <= 0 || x >= 8 || y <= 0 || y >= 8) {
break;
}
// 移動到白象的位置
else if (board[x][y] == 'B') {
break;
} else if (board[x][y] == 'p') {
count++;
break;
}
}
}
return count;
}
}
}
return 0;
}
public static void main(String[] args) {
char[][] boards = {{'.', '.', '.', '.', '.', '.', '.', '.'},
{'.', '.', '.', '.', '.', '.', '.', '.'},
{'.', '.', '.', '.', '.', '.', '.', '.'},
{'.', '.', '.', 'R', '.', '.', '.', '.'},
{'.', '.', '.', '.', '.', '.', '.', '.'},
{'.', '.', '.', '.', '.', '.', '.', '.'},
{'.', '.', '.', '.', '.', '.', '.', '.'},
{'.', '.', '.', '.', '.', '.', '.', '.'}};
int num = new Q11().numRookCapturesV2(boards);
}
}