LeetCode 力扣每日一题 488.祖玛游戏

题目描述:

你正在参与祖玛游戏的一个变种。

在这个祖玛游戏变体中,桌面上有 一排 彩球,每个球的颜色可能是:红色 'R'、黄色 'Y'、蓝色 'B'、绿色 'G' 或白色 'W' 。你的手中也有一些彩球。

你的目标是 清空 桌面上所有的球。每一回合:

从你手上的彩球中选出 任意一颗 ,然后将其插入桌面上那一排球中:两球之间或这一排球的任一端。
接着,如果有出现 三个或者三个以上 且 颜色相同 的球相连的话,就把它们移除掉。
如果这种移除操作同样导致出现三个或者三个以上且颜色相同的球相连,则可以继续移除这些球,直到不再满足移除条件。
如果桌面上所有球都被移除,则认为你赢得本场游戏。
重复这个过程,直到你赢了游戏或者手中没有更多的球。
给你一个字符串 board ,表示桌面上最开始的那排球。另给你一个字符串 hand ,表示手里的彩球。请你按上述操作步骤移除掉桌上所有球,计算并返回所需的 最少 球数。如果不能移除桌上所有的球,返回 -1 。(难度:困难)

原题链接:488. 祖玛游戏 - 力扣(LeetCode) (leetcode-cn.com)

 C++代码:

class Solution {
    int ans, used;
    unordered_map<char, int> rem;
    stack<pair<char, int>> st;

    void dfs(int pos, string &board) {
        if (used > ans)
            return;

        if (pos == board.size()) {
            if (st.empty())
                ans = used;
            return;
        }
        
        if (!st.empty() && st.top().first == board[pos]) {
            st.top().second++;
        } else {
            st.emplace(board[pos], 1);
        }

        if (st.top().second >= 3) {
            if (pos == board.size() || board[pos + 1] != board[pos]) {
            // 后面没有相同颜色的球,可以直接消去
                auto tmp = st.top();    
                st.pop();
                dfs(pos + 1, board);
                st.push(tmp);
            } else {
            // 后面有相同颜色的球,必须插入与当前位置不同色的小球进行分隔
                for (auto [ch, num] : rem) {
                    if (ch == board[pos])
                        continue;
                    for (int j = 1; j <= min(3, num); ++j) {
                        rem[ch] -= j;
                        used += j;
                        auto tmp = st.top();    
                        st.pop();
                        if (!st.empty() && st.top().first == ch) {
                            st.top().second += j;
                        } else {
                            st.emplace(ch, j);
                        }
                        if (st.top().second == 3) {
                            auto tmp2 = st.top();
                            st.pop();
                            dfs(pos + 1, board);
                            st.push(tmp2);
                        } else {
                            dfs(pos + 1, board);
                        }
                        if (st.top().second > j) {
                            st.top().second -= j;
                        } else {
                            st.pop();
                        }
                        st.push(tmp);
                        used -= j;
                        rem[ch] += j;
                    }
                }
            }
        }
        
        // 插入与当前位置同色的小球
        if (rem[board[pos]] >= 1 && (pos == board.size() || board[pos + 1] != board[pos])) {
            int lim = rem[board[pos]];
            for (int i = 1; i <= min(2, lim); ++i) {
                rem[board[pos]] -= i;
                used += i;
                st.top().second += i;
                if (st.top().second >= 3) {
                    auto tmp = st.top();
                    st.pop();
                    dfs(pos + 1, board);
                    st.push(tmp);
                } else {
                    dfs(pos + 1, board);
                }
                st.top().second -= i;
                used -= i;
                rem[board[pos]] += i;
            }
        }
        
        if (st.top().second < 3 || (st.top().second == 3 && pos + 1 < board.size() && board[pos] == board[pos + 1]))
            dfs(pos + 1, board);

        if (st.top().second == 1) {
            st.pop();
        } else {
            st.top().second--;
        }
    }
public:
    int findMinStep(string board, string hand) {
        for (char ch : hand)
            rem[ch]++;

        ans = 1e9;
        used = 0;
        dfs(0, board);
        return ans == 1e9 ? -1 : ans;
    }
};

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值