面試官:祖瑪遊戲玩過麼?我來拷拷你~

題目地址(488. 祖瑪遊戲)

https://leetcode-cn.com/probl...前端

題目描述

回憶一下祖瑪遊戲。如今桌上有一串球,顏色有紅色(R),黃色(Y),藍色(B),綠色(G),還有白色(W)。 如今你手裏也有幾個球。

每一次,你能夠從手裏的球選一個,而後把這個球插入到一串球中的某個位置上(包括最左端,最右端)。接着,若是有出現三個或者三個以上顏色相同的球相連的話,就把它們移除掉。重複這一步驟直到桌上全部的球都被移除。

找到插入並能夠移除掉桌上全部球所需的最少的球數。若是不能移除桌上全部的球,輸出 -1 。

示例:
輸入: "WRRBBW", "RB"
輸出: -1
解釋: WRRBBW -> WRR[R]BBW -> WBBW -> WBB[B]W -> WW (翻譯者標註:手上球已經用完,桌上還剩兩個球沒法消除,返回-1)

輸入: "WWRRBBWW", "WRBRW"
輸出: 2
解釋: WWRRBBWW -> WWRR[R]BBWW -> WWBBWW -> WWBB[B]WW -> WWWW -> empty

輸入:"G", "GGGGG"
輸出: 2
解釋: G -> G[G] -> GG[G] -> empty

輸入: "RBYYBBRRB", "YRBGB"
輸出: 3
解釋: RBYYBBRRB -> RBYY[Y]BBRRB -> RBBBRRB -> RRRB -> B -> B[B] -> BB[B] -> empty
標註:

你能夠假設桌上一開始的球中,不會有三個及三個以上顏色相同且連着的球。
桌上的球不會超過20個,輸入的數據中表明這些球的字符串的名字是 "board" 。
你手中的球不會超過5個,輸入的數據中表明這些球的字符串的名字是 "hand"。
輸入的兩個字符串均爲非空字符串,且只包含字符 'R','Y','B','G','W'。

前置知識

  • 回溯
  • 哈希表
  • 雙指針

公司

  • 百度

思路

面試題困難難度的題目常見的題型有:python

  • DP
  • 設計題
  • 遊戲

本題就是遊戲類題目。 若是你是一個前端, 說不定還會考察你如何實現一個 zuma 遊戲。這種遊戲類的題目,能夠簡單能夠困難, 好比力扣經典的石子游戲,寶石遊戲等。這類題目沒有固定的解法。我作這種題目的思路就是先暴力模擬,再嘗試優化算法瓶頸。git

注意下數據範圍球的數目 <= 5,所以暴力法就變得可行。基本思路是暴力枚舉手上的球能夠消除的地方, 咱們可使用回溯法來完成暴力枚舉的過程,在回溯過程記錄最小值便可。因爲回溯樹的深度不會超過 5,所以這種解法應該能夠 AC。github

上面提到的能夠消除的地方,指的是連續相同顏色 + 手上相同顏色的球大於等於 3,這也是題目說明的消除條件。面試

所以咱們只須要兩個指針記錄連續相同顏色球的位置,若是能夠消除,消除便可。算法

如圖,咱們記錄了連續紅球的位置, 若是手上有紅球, 則能夠嘗試將其清除,這一次決策就是回溯樹(決策樹)的一個分支。以後咱們會撤回到這個決策分支, 嘗試其餘可行的決策分支。優化

以 board = RRBBRR , hand 爲 RRBB 爲例,其決策樹爲:spa

其中虛線表示無需手動干預,系統自動消除。葉子節點末尾的黃色表示所有消除須要的手球個數。路徑上的文字後面的數字表示這次消除須要的手球個數翻譯

若是你對回溯不熟悉,能夠參考下我以前寫的幾篇題解:好比 46.permutations

能夠看出, 若是選擇先消除中間的藍色,則只須要一步便可完成。設計

關於計算連續球位置的核心代碼(Python3):

i = 0
while i < len(board):
    j = i + 1
    while j < len(board) and board[i] == board[j]: j += 1
    # 其餘邏輯

    # 更新左指針
    i = j

具體算法:

  1. 用哈希表存儲手上的球的種類和個數,這麼作是爲了後面快速判斷連續的球是否能夠被消除。因爲題目限制手上求不會超過 5,所以哈希表的最大容量就是 5,能夠認爲這是一個常數的空間。
  2. 回溯。

    2.1 確承認以消除的位置,算法參考上面的代碼。

    2.2 判斷手上是否有足夠相同顏色的球能夠消除。

    2.3 回溯的過程記錄全局最小值。

代碼

代碼支持:Python3

Python3 Code:

class Solution:
    def findMinStep(self, board: str, hand: str) -> int:
        def backtrack(board):
            if not board: return 0
            i = 0
            ans = 6
            while i < len(board):
                j = i + 1
                while j < len(board) and board[i] == board[j]: j += 1
                balls = 3 - (j - i)
                if counter[board[i]] >= balls:
                    balls = max(0, balls)
                    counter[board[i]] -= balls
                    ans = min(ans, balls + backtrack(board[:i] + board[j:]))
                    counter[board[i]] += balls
                i = j
            return ans

        counter = collections.Counter(hand)
        ans = backtrack(board)
        return -1 if ans > 5 else ans

複雜度分析

  • 時間複雜度:$O(2^(min(C, 5)))$,其中 C 爲連續相同顏色球的次數,好比 WWRRRR, C 就是 2, WRBDD, C 就是 4。min(C, 5) 是由於題目限定了手上球的個數不大於 5。
  • 空間複雜度:$O(min(C, 5) * Board)$,其中 C 爲連續相同顏色球的次數,Board 爲 Board 的長度。

關鍵點解析

  • 回溯模板
  • 雙指針寫法

你們對此有何見解,歡迎給我留言,我有時間都會一一查看回答。更多算法套路能夠訪問個人 LeetCode 題解倉庫:https://github.com/azl3979858... 。 目前已經 36K star 啦。你們也能夠關注個人公衆號《力扣加加》帶你啃下算法這塊硬骨頭。

相關文章
相關標籤/搜索