2021.11.9 力扣-每日一题-祖玛游戏

这篇博客介绍了如何利用记忆化搜索和回溯算法解决一个祖玛游戏的变体。作者详细阐述了算法的实现过程,包括从手中选择彩球插入桌面,检查并移除相同颜色的球链,以及如何递归处理连锁反应。在解决过程中,作者遇到了挑战,如字符串操作和状态记录,并最终成功完成。博客强调了字符串处理技巧和在深度优先搜索中使用记忆化的重要性。
摘要由CSDN通过智能技术生成

题目描述:

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

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

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

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

方法一(记忆化搜索+回溯):

class Solution {
public:
    int inf = 6;
    //记录搜索过的状态,对应的数字为该状态的最小操作数
    unordered_map<string, int> state;
    //从j开始向左右扩散,消除都是newboard[j]的字符
    string remove(string& newboard, int j)
    {
        if (newboard.size() == 0)
        {
            return newboard;
        }
        int left = j;
        int right = j;
        while (left - 1 >= 0 && newboard[left - 1] == newboard[left])
        {
            left--;
        }
        while (right + 1 <= newboard.size() && newboard[right + 1] == newboard[right])
        {
            right++;
        }
        //count是相同的字符的个数,大于等于3则删除
        int count = right - left + 1;
        if (count >= 3)
        {
            newboard.erase(left, count);
            //递归,用来解决链锁反应
            return remove(newboard, left);
        }
        return newboard;
    }

    int dfs(string& curboard, vector<char>& curhand)
    {
        //如果已经消除完了,就返回0
        if (curboard.size() == 0)
        {
            return 0;
        }
        //记忆化搜索,出现相同的状态就返回
        if (state.count(curboard))
        {
            return state[curboard];
        }

        int ans = inf;
        //将手中的球插入不同的位置中
        for (int i = 0; i < curhand.size(); i++)
        {
            char ch = curhand[i];
            //如果ch == '0',说明这个球已经用过了
            if (ch != '0')
            {
                for (int j = 0; j < curboard.size(); j++)
                {
                    string newboard;
                    newboard += curboard.substr(0, j);
                    newboard.push_back(ch);
                    newboard += curboard.substr(j);
                    //进行删除操作
                    newboard = remove(newboard, j);
                    //在进入下一层递归之前,将curhand[i]设为'0',表示这个球已经用过了
                    curhand[i] = '0';
                    ans = min(ans, dfs(newboard, curhand) + 1);
                    //回溯,恢复状态
                    curhand[i] = ch;
                }
            }
        }
        //记录当前状态已经被搜索过了
        state[curboard] = ans;
        return ans;
    }
    int findMinStep(string board, string hand) {
        vector<char> curhand(hand.size());
        //不知道为什么,vector<char>不能够使用push_back()函数,只能用赋值了
        for (int i = 0; i < curhand.size(); i++)
        {
            curhand[i] = hand[i];
        }
        int ans = dfs(board, curhand);
        return ans == inf ? -1 : ans;
    }
};

今天这道题真是写到要吐了,看着题解都写了半天,写完之后又debug了半天。

看到最小操作数的字眼,本想用bfs,但这题的board和hand是随时变化的,所以没能写出来,还是用了最简单的dfs来做。

这道题还是颇有收获的,加强学习了一下字符串的截取、删除、添加操作,还有第一次在dfs中使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值