2021-11-09祖玛游戏
488. 祖玛游戏
难度困难208
你正在参与祖玛游戏的一个变种。
在这个祖玛游戏变体中,桌面上有 一排 彩球,每个球的颜色可能是:红色 'R'
、黄色 'Y'
、蓝色 'B'
、绿色 'G'
或白色 'W'
。你的手中也有一些彩球。
你的目标是 清空 桌面上所有的球。每一回合:
- 从你手上的彩球中选出 任意一颗 ,然后将其插入桌面上那一排球中:两球之间或这一排球的任一端。
- 接着,如果有出现 三个或者三个以上 且 颜色相同 的球相连的话,就把它们移除掉。
- 如果这种移除操作同样导致出现三个或者三个以上且颜色相同的球相连,则可以继续移除这些球,直到不再满足移除条件。
- 如果桌面上所有球都被移除,则认为你赢得本场游戏。
- 重复这个过程,直到你赢了游戏或者手中没有更多的球。
给你一个字符串 board
,表示桌面上最开始的那排球。另给你一个字符串 hand
,表示手里的彩球。请你按上述操作步骤移除掉桌上所有球,计算并返回所需的 最少 球数。如果不能移除桌上所有的球,返回 -1
。
示例 1:
输入:board = "WRRBBW", hand = "RB" 输出:-1 解释:无法移除桌面上的所有球。可以得到的最好局面是: - 插入一个 'R' ,使桌面变为 WRRRBBW 。WRRRBBW -> WBBW - 插入一个 'B' ,使桌面变为 WBBBW 。WBBBW -> WW 桌面上还剩着球,没有其他球可以插入。
示例 2:
输入:board = "WWRRBBWW", hand = "WRBRW" 输出:2 解释:要想清空桌面上的球,可以按下述步骤: - 插入一个 'R' ,使桌面变为 WWRRRBBWW 。WWRRRBBWW -> WWBBWW - 插入一个 'B' ,使桌面变为 WWBBBWW 。WWBBBWW -> WWWW -> empty 只需从手中出 2 个球就可以清空桌面。
示例 3:
输入:board = "G", hand = "GGGGG" 输出:2 解释:要想清空桌面上的球,可以按下述步骤: - 插入一个 'G' ,使桌面变为 GG 。 - 插入一个 'G' ,使桌面变为 GGG 。GGG -> empty 只需从手中出 2 个球就可以清空桌面。
示例 4:
输入:board = "RBYYBBRRB", hand = "YRBGB" 输出:3 解释:要想清空桌面上的球,可以按下述步骤: - 插入一个 'Y' ,使桌面变为 RBYYYBBRRB 。RBYYYBBRRB -> RBBBRRB -> RRRB -> B - 插入一个 'B' ,使桌面变为 BB 。 - 插入一个 'B' ,使桌面变为 BBB 。BBB -> empty 只需从手中出 3 个球就可以清空桌面。
提示:
1 <= board.length <= 16
1 <= hand.length <= 5
board
和hand
由字符'R'
、'Y'
、'B'
、'G'
和'W'
组成- 桌面上一开始的球中,不会有三个及三个以上颜色相同且连着的球
通过次数14,246提交次数27,078
方法一:广度优先搜索
思路
根据题目要求,桌面上最多有 1616 个球,手中最多有 55 个球;我们可以以任意顺序在 55 个回合中使用手中的球;在每个回合中,我们可以选择将手中的球插入到桌面上任意两球之间或这一排球的任意一端。
因为插入球的颜色和位置的选择是多样的,选择的影响也可能在多次消除操作之后才能体现出来,所以通过贪心方法根据当前情况很难做出全局最优的决策。实际每次插入一个新的小球时,并不保证插入后一定可以消除,因此我们需要搜索和遍历所有可能的插入方法,找到最小的插入次数。比如以下测试用例:
桌面上的球为 \texttt{RRWWRRBBRR}RRWWRRBBRR,手中的球为 \texttt{WB}WB,如果我们按照贪心法每次插入进行消除就会出现无法完全消除。
因此,我们使用广度优先搜索来解决这道题。即对状态空间进行枚举,通过穷尽所有的可能来找到最优解,并使用剪枝的方法来优化搜索过程。
为什么使用广度优先搜索?
我们不妨规定,每一种不同的桌面上球的情况和手中球的情况的组合都是一种不同的状态。对于相同的状态,其清空桌面上球所需的回合数总是相同的;而不同的插入球的顺序,也可能得到相同的状态。因此,如果使用深度优先搜索,则需要使用记忆化搜索,以避免重复计算相同的状态。
因为只需要找出需要回合数最少的方案,因此使用广度优先搜索可以得到可以消除桌面上所有球的方案时就直接返回结果,而不需要继续遍历更多需要回合数更多的方案。而广度优先搜索虽然需要在队列中存储较多的状态,但是因为使用深度优先搜索也需要存储这些状态及这些状态对应的结果,因此使用广度优先搜索并不会需要更多的空间。
算法
在算法的实现中,我们可以通过以下方法来实现广度优先:
使用队列来维护需要处理的状态队列,使用哈希集合存储已经访问过的状态。每一次取出队列中的队头状态,考虑其中所有可以插入球的方案,如果新方案还没有被访问过,则将新方案添加到队列的队尾。
下面,我们考虑剪枝条件:
第 11 个剪枝条件:手中颜色相同的球每次选择时只需要考虑其中一个即可
如果手中有颜色相同的球,那么插入这些球中的哪一个都没有区别。因此,手中颜色相同的球,我们只需要考虑其中一个即可。在具体的实现中,我们可以先将手中的球排序,如果当前遍历的球的颜色和上一个遍历的球的颜色相同,则跳过当前遍历的球。
第 22 个剪枝条件:只在连续相同颜色的球的开头位置或者结尾位置插入新的颜色相同的球
如果桌面上有一个红球,那么在其左侧和右侧插入一个新的红球没有区别;同理,如果桌面上有 22 个连续的红球,那么在其左侧、中间和右侧插入一个新的红球没有区别。因此,如果新插入的球和桌面上某组连续颜色相同的球(也可以是 11 个)的颜色相同,我们只需要考虑在其左侧插入新球的情况即可。在具体的实现中,如果新插入的球和插入位置左侧的球的颜色相同,则跳过这个位置。
第 33 个剪枝条件:只考虑放置新球后有可能得到更优解的位置
考虑插入新球的颜色与插入位置周围球的颜色的情况,在已经根据第 22 个剪枝条件剪枝后,还可能出现如下三种情况:插入新球与插入位置右侧的球颜色相同;插入新球与插入位置两侧的球颜色均不相同,且插入位置两侧的球的颜色不同;插入新球与插入位置两侧的球颜色均不相同,且插入位置两侧的球的颜色相同。
对于「插入新球与插入位置右侧的球颜色相同」的情况,这种操作可能可以构成连续三个相同颜色的球实现消除,是有可能得到更优解的。读者可以结合以下例子理解。
例如:桌面上的球为 \texttt{WWRRBBWW}WWRRBBWW,手中的球为 \texttt{WWRB}WWRB,答案为 22。
操作方法如下:\texttt{WWRRBBWW} \rightarrow \texttt{WW(R)RRBBWW} \rightarrow \texttt{WWBBWW} \rightarrow \texttt{WW(B)BBWW} \rightarrow \texttt{WWWW} \rightarrow \texttt{""}WWRRBBWW→WW(R)RRBBWW→WWBBWW→WW(B)BBWW→WWWW→""。
对于「插入新球与插入位置两侧的球颜色均不相同,且插入位置两侧的球的颜色不同」的情况,这种操作可以将连续相同颜色的球拆分到不同的组合中消除,也是有可能得到更优解的。读者可以结合以下例子理解。
例如:桌面上的球为 \texttt{RRWWRRBBRR}RRWWRRBBRR,手中的球为 \texttt{WB}WB,答案为 22。
操作方法如下:\texttt{RRWWRRBBRR} \rightarrow \texttt{RRWWRRBBR(W)R} \rightarrow \texttt{RRWWRR(B)BBRWR} \rightarrow \texttt{RRWWRRRWR} \rightarrow \texttt{RRWWWR} \rightarrow \texttt{RRR} \rightarrow \texttt{""}RRWWRRBBRR→RRWWRRBBR(W)R→RRWWRR(B)BBRWR→RRWWRRRWR→RRWWWR→RRR→""。
对于「插入新球与插入位置两侧的球颜色均不相同,且插入位置两侧的球的颜色相同」的情况,这种操作并不能对消除顺序产生任何影响。如插入位置旁边的球可以消除的话,那么这种插入方法与直接将新球插入到与之颜色相同的球的旁边没有区别。因此,这种操作不能得到比「插入新球与插入位置右侧的球颜色相同」更好的情况,得到更优解。读者可以结合以下例子理解。
例如:桌面上的球为 \texttt{WWRRBBWW}WWRRBBWW,手中的球为 \texttt{WWRB}WWRB,答案为 22。
操作方法如下:\texttt{WWRRBBWW} \rightarrow \texttt{WWRRBB(R)WW} \rightarrow \texttt{WWRRB(B)BRWW} \rightarrow \texttt{WWRRRWW} \rightarrow \texttt{WWWW} \rightarrow \texttt{""}WWRRBBWW→WWRRBB(R)WW→WWRRB(B)BRWW→WWRRRWW→WWWW→""。
细节
题目规定了如果在消除操作后,如果导致出现了新的连续三个或者三个以上颜色相同的球,则继续消除这些球,直到不再满足消除条件,实际消除时我们可以利用栈的特性,每次遇到连续可以消除的球时,我们就将其从栈中弹出。在实现中,我们可以在遍历桌面上的球时,使用列表维护遍历过的每种球的颜色和连续数量,从而通过一次遍历消除连续三个或者三个以上颜色相同的球。具体地:
使用 \textit{visited\_ball}visited_ball 维护遍历过的每种球的颜色和连续数量,设其中最后一个颜色 \textit{last\_color}last_color,其连续数量为 \textit{last\_num}last_num;遍历桌面上的球,设当前遍历到的球为 \textit{cur\_ball}cur_ball,其颜色为 \textit{cur\_color}cur_color。
首先,判断:
如果 \textit{visited\_ball}visited_ball 不为空,且 \textit{cur\_color}cur_color 与 \textit{last\_color}last_color 不同,则判断:如果 \textit{last\_num}last_num 大于等于 33,则从 \textit{visited\_ball}visited_ball 中移除 \textit{last\_color}last_color 和 \textit{last\_num}last_num。
接着,判断:
如果 \textit{visited\_ball}visited_ball 为空,或 \textit{cur\_color}cur_color 与 \textit{last\_color}last_color 不同,则向 \textit{visited\_ball}visited_ball 添加 \textit{cur\_color}cur_color 及连续数量 11;
否则,累加 \textit{last\_num}last_num。
最后,根据列表中维护的每种球的颜色和连续数量,重新构造桌面上的球的组合即可。
在 \texttt{Python}Python 中,因为对正则表达式的优化较好,也可以循环地使用正则表达式来消除连续三个或者三个以上颜色相同的球。
class Solution:def findMinStep(self, board: str, hand: str) -> int:def clean(s):# 消除桌面上需要消除的球n = 1while n:s, n = re.subn(r"(.)\1{2,}", "", s)return shand = "".join(sorted(hand))# 初始化用队列维护的状态队列:其中的三个元素分别为桌面球状态、手中球状态和回合数queue = deque([(board, hand, 0)])# 初始化用哈希集合维护的已访问过的状态visited = {(board, hand)}while queue:cur_board, cur_hand, step = queue.popleft()for i, j in product(range(len(cur_board) + 1), range(len(cur_hand))):# 第 1 个剪枝条件: 当前球的颜色和上一个球的颜色相同if j > 0 and cur_hand[j] == cur_hand[j - 1]:continue# 第 2 个剪枝条件: 只在连续相同颜色的球的开头位置插入新球if i > 0 and cur_board[i - 1] == cur_hand[j]:continue# 第 3 个剪枝条件: 只在以下两种情况放置新球# - 第 1 种情况 : 当前球颜色与后面的球的颜色相同# - 第 2 种情况 : 当前后颜色相同且与当前颜色不同时候放置球 choose = Falseif 0 < i < len(cur_board) and cur_board[i - 1] == cur_board[i] and cur_board[i - 1] != cur_hand[j]:choose = Trueif i < len(cur_board) and cur_board[i] == cur_hand[j]:choose = Trueif choose:new_board = clean(cur_board[:i] + cur_hand[j] + cur_board[i:])new_hand = cur_hand[:j] + cur_hand[j + 1:]if not new_board:return step + 1if (new_board, new_hand) not in visited:queue.append((new_board, new_hand, step + 1))visited.add((new_board, new_hand))return -1
2021-11-09祖玛游戏相关推荐
- 2021.11.09 - 144.祖玛游戏
文章目录 1. 题目 2. 思路 (1) DFS+记忆化搜索 3. 代码 1. 题目 2. 思路 (1) DFS+记忆化搜索 过于复杂,建议背诵默写. 3. 代码 import java.util.H ...
- 牛客小月赛 j-洋灰三角 2021.11.09
在这里插入图片描述 运用算法:矩阵乘法,乘法逆元. 学习矩阵乘法+乘法逆元就 可以ac本题 解题代码
- 2021/11/07-2021/11/11
# -*- coding = utf-8 -*- # @Time:2021/11/7 16:09 # @Author:zhangchuhan # @File:demo01.py # @Software ...
- 【跃迁之路】【636天】程序员高效学习方法论探索系列(实验阶段393-2018.11.09)...
@(收集箱(每日一记,每周六整理))专栏 实验说明 从2017.10.6起,开启这个系列,目标只有一个:探索新的学习方法,实现跃迁式成长 实验期2年(2017.10.06 - 2019.10.06) ...
- 【不忘初心】Win10_LTSC2021_19044.1381_X64_可更新[纯净精简版][2.52G](2021.11.20)
此版可正常更新补丁,母版来自UUP WIN10_LTSC2021 19044.1288集成补丁到19044.1381为了保证稳定初心的系统全部都是离线精简和优化,非二次封装.系统纯净.流畅.进程少无任 ...
- android+祖玛游戏源码,unity祖玛游戏Zuma Ball Blast源码
压缩包内容概览: unity祖玛游戏Zuma Ball src ; 汇编C锐器编辑器 ; 汇编-C夏普编辑器 ; 组件-C夏普vs ; C夏普组件 ; 汇编统一脚本vs ; 汇编统一体脚本 ; 资产 ...
- Pygame从0实战11(泡泡小游戏完成)
1.Pygame从0实战11(泡泡小游戏完成) 主要工作:绘制摩擦玻璃面板.改变鼠标图标样式.添加小球入洞音效和游戏胜利音效 # -*- coding: utf-8 -*- # @Author: Cl ...
- 【2021年9月游戏行业网络关注度榜】大IP新玩法吸引玩家 网易再出爆款手游
2021年9月,中国游戏行业继续稳步发展.新浪游戏联合微热点研究院&新浪舆情通推出<2021年9月游戏网络关注度分析报告>,以下为报告详情: 9月最热手游--王者荣耀 据微热点研究 ...
- 【不忘初心】Windows11 22000.318 X64 四合一[纯净精简版][2.62G](2021.11.10)
此版可正常更新补丁,WIN11全新的UI界面出炉!可以说这一次Windows 11全新升级,无论是从Logo上还是UI界面设计,都有很大的变化,母版来自UUP WIN11_22000.318,为了保证 ...
最新文章
- 做时间序列预测有必要用深度学习吗?事实证明,梯度提升回归树媲美甚至超越多个DNN模型...
- puts遇到空格无法输出_输入一句英文,只包含字母和空格,如何输出这句英文中.....-黑马程序员技术交流社区...
- 为什么不用量子计算机挖比特币,Pieter Wuille:如果你有一台足够强的量子计算机,你能偷取多少比特币?...
- linux网络编程之posix 线程(三):posix 匿名信号量与互斥锁 示例生产者--消费者问题
- (计算机组成原理)第五章中央处理器-第四节2:微程序控制器基本原理
- SUN公司经典linux教材转自http://blog.chinaunix.net/uid-20446831-id-1677336.html
- java开发之路——个人开发模板之技巧
- Canvas 超详细
- maven+scala和java_maven打包scala+java工程
- GTK、Qt和wxWidgets
- 软件需求工程 高校教学平台 项目总体计划
- List转Map的几种方式
- 设置计算机网络文件共享,局域网电脑文件共享怎么设置
- 【杂谈】MacPro 2015款拆机清灰换导热硅脂实录
- b站修改密码服务器错误,提示账号或者密码错误,无法正常登陆
- Could not run ‘aten::slow_conv3d_forward‘ with arguments from the ‘CUDA‘ bac
- SpringBoot + Element UI 楠橘星后台管理系统一键打包部署教程文档
- 一个小白对接电子面单的哪些坑?
- C语言-学生成绩链表处理
- 第九批车船税减免名单公示 新能源汽车共计444款