車的可用捕獲量

leetcode 每日一題

題目:車的可用捕獲量

在一個 8 x 8 的棋盤上,有一個白色車(rook)。也可能有空方塊,白色的象(bishop)和黑色的卒(pawn)。它們分別以字符 “R”,“.”,“B” 和 “p” 給出。

大寫字符表示白棋,小寫字符表示黑棋。

車按國際象棋中的規則移動:它選擇四個基本方向中的一個(北,東,西和南),然後朝那個方向移動,直到它選擇停止、到達棋盤的邊緣或移動到同一方格來捕獲該方格上顏色相反的卒。另外,車不能與其他友方(白色)象進入同一個方格。

返回車能夠在一次移動中捕獲到的卒的數量。

示例1:

示例1

輸入:
[[".", ".", ".", ".", ".", ".", ".", "."],
[".", ".", ".", "p", ".", ".", ".", "."],
[".", ".", ".", "R", ".", ".", ".", "p"], 
[".", ".", ".", ".", ".", ".", ".", "."],
[".", ".", ".", ".", ".", ".", ".", "."], 
[".", ".", ".", "p", ".", ".", ".", "."],
[".", ".", ".", ".", ".", ".", ".", "."], 
[".", ".", ".", ".", ".", ".", ".", "."]]
輸出:3
解釋:在本例中,車能夠捕獲所有的卒。

示例2:

示例2

輸入:
[[".", ".", ".", ".", ".", ".", ".", "."],
[".", "p", "p", "p", "p", "p", ".", "."],
[".", "p", "p", "B", "p", "p", ".", "."],
[".", "p", "B", "R", "B", "p", ".", "."],
[".", "p", "p", "B", "p", "p", ".", "."], 
[".", "p", "p", "p", "p", "p", ".", "."],
[".", ".", ".", ".", ".", ".", ".", "."], 
[".", ".", ".", ".", ".", ".", ".", "."]]
輸出:0
解釋:
象阻止了車捕獲任何卒。

示例3:

示例3

輸入:
[[".", ".", ".", ".", ".", ".", ".", "."], 
[".", ".", ".", "p", ".", ".", ".", "."],
[".", ".", ".", "p", ".", ".", ".", "."], 
["p", "p", ".", "R", ".", "p", "B", "."], 
[".", ".", ".", ".", ".", ".", ".", "."], 
[".", ".", ".", "B", ".", ".", ".", "."],
[".", ".", ".", "p", ".", ".", ".", "."],
[".", ".", ".", ".", ".", ".", ".", "."]]
輸出:3
解釋: 
車可以捕獲位置 b5,d6 和 f5 的卒。

解題方法

題目分析

題目上面有一句話可能會比較誤導大家:返回車能夠在一次移動中捕獲到的卒的數量。

但結合給出的示例來看,其實最後要求的每次可以喫到卒的方案有幾種

車可以朝上下左右四個方向移動,移動的路徑上面有卒就可以捕捉,但一條路上只能喫一次卒,而且移動的時候如果碰到自己的象還會被阻擋

所以我們只需要找到多少個車和卒可以直接相連且沒有阻礙的就行了。

方法一

先找出車(R)的位置
再找出卒(p)的位置
同樣象(B)的位置也找出來

所有的棋子的座標都找出來之後,我們再看一下車和每個卒之間有沒有阻礙,有阻礙的就捨棄掉不能捕捉,沒有阻礙的就可以捕捉result+1

class Solution1(object):
    def numRookCaptures(self, board):
        """
        :type board: List[List[str]]
        :rtype: int
        """
        # 先找出 R 的座標
        R_index = [(line, index) for line in range(8) for index in range(8) if board[line][index] == 'R'][0]
        # 找出 B 的座標
        B_index = [(line, index) for line in range(8) for index in range(8) if board[line][index] == 'B']
        # 找出 p 的座標
        p_index = [(line, index) for line in range(8) for index in range(8) if board[line][index] == 'p']
        # 先忽略B的存在,找出能被 R 捕捉到的 p
        catch_p = [row for row in p_index if row[0] == R_index[0] or row[1] == R_index[1]]
        # R和p之間那些可能被遮擋的點
        result = 0
        for row in catch_p:
            # 當R和p在同一排
            if row[0] == R_index[0]:
                before, after = min(row[1], R_index[1]), max(row[1], R_index[1])
                # 計算有無遮擋
                occlude = [(row[0], i) for i in range(before + 1, after) if
                           (row[0], i) in B_index or (row[0], i) in catch_p]
                # 如果沒有被遮擋則可以捕捉
                if not occlude: result += 1
            # 當R和p在同一列
            if row[1] == R_index[1]:
                before, after = min(row[0], R_index[0]), max(row[0], R_index[0])
                occlude = [(i, row[1]) for i in range(before + 1, after) if
                           (i, row[1]) in B_index or (i, row[1]) in catch_p]
                if not occlude: result += 1
        return result

方法二

這個方法和1有點類似,但出發點不同
這裏我們只需要找出車®的位置,再從R的位置開始朝上下左右四個方向進攻
如果前進的過程碰到了象(B)那這條路就走不通了
如果前進的時候沒有遇到象,然後捕捉到了一個卒(p),那麼在這條路上的進攻也就結束了,因爲每條路只能捕捉一個卒

class Solution2(object):
    def numRookCaptures(self, board):
        R_index = [(line, index) for line in range(8) for index in range(8) if board[line][index] == 'R'][0]
        row_index, clo_index = R_index[0], R_index[1]
        print(R_index)
        # 從R的上下左右擴散尋找
        result = 0
        # 上
        for row in range(row_index - 1, -1, -1):
            if board[row][clo_index] == 'p':
                result += 1
                break
            elif board[row][clo_index] == 'B':
                break
        # 下
        for row in range(row_index + 1, 8):
            if board[row][clo_index] == 'p':
                result += 1
                break
            elif board[row][clo_index] == 'B':
                break
        print(result)
        # 左
        for clo in range(clo_index - 1, -1, -1):
            if board[row_index][clo] == 'p':
                result += 1
                break
            elif board[row_index][clo] == 'B':
                break
        # 右
        for clo in range(clo_index + 1, 8):
            if board[row_index][clo] == 'p':
                result += 1
                break
            elif board[row_index][clo] == 'B':
                break
        return result

方法三

這個方法相比前面兩個有點取巧,但是中心思想還是不變,就是找到車和卒相鄰即"pR"或"Rp"即可

首先是橫向搜索,將每橫的棋子連起來,然後再將所有橫的棋子連起來,因爲每橫的棋子是要分開搜索的所以我這裏用了“,”隔開。
然後是縱向搜索,同樣是將每列的棋子連起來,然後再找出pR和Rp
在縱向搜索的時候,我是先把矩陣進行了轉置即將棋盤旋轉了90度,然後如再按橫向搜索的方法進行查找。

class Solution3(object):
    def numRookCaptures(self, board):
        # 橫向數據組成字符串
        rowStr = ','.join([''.join(row).replace('.', '') for row in board])
        # 將矩陣轉置一下
        board = [[row[i] for row in board] for i in range(8)]
        # 縱向數據組成字符串
        cloStr = ','.join([''.join(row).replace('.', '') for row in board])
        return sum([rowStr.count("pR"), rowStr.count("Rp"), cloStr.count("pR"), cloStr.count("Rp")]

以上就是今天每日一題的三種不同解法,但其實都是大同小異。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章