[LeetCode] Zuma Game 祖瑪游戲


 

Think about Zuma Game. You have a row of balls on the table, colored red(R), yellow(Y), blue(B), green(G), and white(W). You also have several balls in your hand.

Each time, you may choose a ball in your hand, and insert it into the row (including the leftmost place and rightmost place). Then, if there is a group of 3 or more balls in the same color touching, remove these balls. Keep doing this until no more balls can be removed.

Find the minimal balls you have to insert to remove all the balls on the table. If you cannot remove all the balls, output -1.

Examples:
Input: "WRRBBW", "RB" Output: -1 Explanation: WRRBBW -> WRR[R]BBW -> WBBW -> WBB[B]W -> WW Input: "WWRRBBWW", "WRBRW" Output: 2 Explanation: WWRRBBWW -> WWRR[R]BBWW -> WWBBWW -> WWBB[B]WW -> WWWW -> empty Input:"G", "GGGGG" Output: 2 Explanation: G -> G[G] -> GG[G] -> empty Input: "RBYYBBRRB", "YRBGB" Output: 3 Explanation: RBYYBBRRB -> RBYY[Y]BBRRB -> RBBBRRB -> RRRB -> B -> B[B] -> BB[B] -> empty

Note:

    1. You may assume that the initial row of balls on the table won’t have any 3 or more consecutive balls with the same color.
    2. The number of balls on the table won't exceed 20, and the string represents these balls is called "board" in the input.
    3. The number of balls in your hand won't exceed 5, and the string represents these balls is called "hand" in the input.
    4. Both input strings will be non-empty and only contain characters 'R','Y','B','G','W'.

 

這道題說的就是著名的祖瑪游戲了,讓我想起了以前玩過的泡泡龍,也是一種祖瑪游戲,在QQ上也有泡泡龍的游戲,還可以使用各種道具害其他玩家,相當有趣。那么這道題是一種簡化版的祖瑪游戲,只是一個一維數組,而且通過限定桌面上的球不超過20個,手里的球不超過5個來降低來難度,貌似是在暗示我們可以用暴力搜索法來做。這道題比較使用遞歸的方法來做,通過遍歷所有可能的情況來找出最優解,題目希望我們用最少的球來消掉桌上所有的球,如果不能完全消掉,返回-1。我們使用哈希表來統計手中每種球的個數,然后我們遍歷桌上的球,我們找連續相同球的個數,在沒有可以消除的情況下,連續的個數只能是1個或2個,然后我們用3減去連續個數,就是我們需要補充的球數以使其可以被消除,那么我們在哈希表表中看我們手中的該類型的球夠不夠,如果夠就表示可以消除,我們在哈希表中減去需要使用掉的球數,然后將消掉的球移除,對新的字符串調用遞歸,如果可以成功消除,會返回一個結果,該結果加上之前需要的球數用來更新結果res,注意調用完遞歸要恢復哈希表的狀態。還有就是在剛進入遞歸函數時,我們要檢測字符串,去除連續3個相同球的情況,這個去除函數也是個遞歸函數,寫起來很簡潔,但是很強大,參見代碼如下:

 

解法一:

class Solution {
public:
    int findMinStep(string board, string hand) {
        int res = INT_MAX;
        unordered_map<char, int> m;
        for (char c : hand) ++m[c];
        res = helper(board, m);
        return res == INT_MAX ? -1 : res;
    }
    int helper(string board, unordered_map<char, int>& m) {
        board = removeConsecutive(board);
        if (board.empty()) return 0;
        int cnt = INT_MAX, j = 0;
        for (int i = 0; i <= board.size(); ++i) {
            if (i < board.size() && board[i] == board[j]) continue;
            int need = 3 - (i - j);
            if (m[board[j]] >= need) {
                m[board[j]] -= need;
                int t = helper(board.substr(0, j) + board.substr(i), m);
                if (t != INT_MAX) cnt = min(cnt, t + need);
                m[board[j]] += need;
            }
            j = i;
        }
        return cnt;
    }
    string removeConsecutive(string board) {
        for (int i = 0, j = 0; i <= board.size(); ++i) {
            if (i < board.size() && board[i] == board[j]) continue;
            if (i - j >= 3) return removeConsecutive(board.substr(0, j) + board.substr(i));
            else j = i;
        }
        return board;
    }
};

 

下面這種解法也是遞歸解法,但是思路和上面略有不同,這里我們不使用哈希表,而是使用一個集合,我們遍歷手中的所有小球,如果某個小球已經在集合中存在了,說明我們已經處理過該小球了,直接跳過,否則就將該小球加入集合中。然后我們遍歷桌上的小球,尋找和當前手中小球一樣的位置,然后將手中小球加入當前位置,調用去除重復3個小球的函數,如果此時字符串為0了,說明當前桌上小球已經完全消掉了,返回1,因為我們此時只使用了一個小球;否則就將手中的當前小球去掉,對新的桌面和剩余手中的小球調用遞歸,如果得到的結果不是-1,我們用此結果加1來更新結果res,參見代碼如下:

 

解法二:

class Solution {
public:
    int findMinStep(string board, string hand) {
        int res = INT_MAX;
        unordered_set<char> s;
        for (int i = 0; i < hand.size(); ++i) {
            if (s.count(hand[i])) continue;
            s.insert(hand[i]);
            for (int j = 0; j < board.size(); ++j) {
                if (board[j] != hand[i]) continue;
                string newBoard = board, newHand = hand;
                newBoard.insert(j, 1, hand[i]);
                newBoard = removeConsecutive(newBoard);
                if (newBoard.size() == 0) return 1;
                newHand.erase(i, 1);
                int cnt = findMinStep(newBoard, newHand);
                if (cnt != -1) res = min(res, cnt + 1);
            }
        }
        return res == INT_MAX ? -1 : res;
    }
    string removeConsecutive(string board) {
        for (int i = 0, j = 0; i <= board.size(); ++i) {
            if (i < board.size() && board[i] == board[j]) continue;
            if (i - j >= 3) return removeConsecutive(board.substr(0, j) + board.substr(i));
            else j = i;
        }
        return board;
    }
};

 

類似題目:

Burst Balloons

Remove Boxes

Strange Printer

 

參考資料:

https://discuss.leetcode.com/topic/76360/bfs

https://discuss.leetcode.com/topic/75578/simplest-method/2

https://discuss.leetcode.com/topic/79820/short-java-solution-beats-98

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM