[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:
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.
The number of balls on the table won't exceed 20, and the string represents these balls is called "board" in the input.
The number of balls in your hand won't exceed 5, and the string represents these balls is called "hand" in the input.
Both input strings will be non-empty and only contain characters 'R','Y','B','G','W'.
思路
需要注意的是,题目已经提供了一些条件。
实现
//
//
#include "../PreLoad.h"
#define MaxNum 6 //随意设定的值,只要比手中的球的数量多即可
class Solution {
public:
/**
* 第一种方法
* @param board
* @param hand
* @return
*/
int findMinStep(string board, string hand) {
sort(hand.begin(), hand.end());
int res = helper(board, hand);
return res > hand.size() ? -1 : res;
}
/**
* 遍历hand中的球,根据手中的球去找board里面的球
* 如果board中存在连续两种一样的球,则进行递归消除
* 或者是hand中存在连续两个一样的球,board中只有一个球的情况,同样进行递归删除
*/
int helper(string board, string hand) {
if (board.empty()) {
return 0;
}
// board没消完,但是手中已经没有球,返回一个大值
if (hand.empty()) {
return MaxNum;
}
int res = MaxNum;
for (int i = 0; i < hand.size(); i++) {
int j = 0;
int n = board.size();
while (j < n) {
// 找hand中的元素,不存在则返回
int k = (int)board.find(hand[i], j);
if (k == string::npos) {
break;
}
// board中存在两个hand[i]
if (k < n-1 && board[k] == board[k+1]) {
string next_board = nextStr(board.substr(0, k) + board.substr(k+2));
// 已经没有什么可以消的了
if (next_board.empty()) {
return 1;
}
string next_hand = hand;
next_hand.erase(next_hand.begin() + i);
res = min(res, helper(next_board, next_hand) + 1);
k++; //因为下面会移动一位,所以这里要提前移动一位
}
// board中不能消hand[i],但是hand中存在两个hand[i]
else if (i < hand.size()-1 && hand[i] == hand[i+1]) {
string next_board = nextStr(board.substr(0, k) + board.substr(k+1));
if (next_board.empty()) {
return 2;
}
string next_hand = hand;
next_hand.erase(i, 2);
res = min(res, helper(next_board, next_hand) + 2);
}
j = k+1;
}
}
return res;
}
// 删除字符串中连续的重复的3个以上的同样的字母
string nextStr(string str) {
while (!str.empty()) {
int start = 0;
bool isremove = false;
for (int i = 0; i <= str.length(); i++) {
if (i == str.length() || str[i] != str[start]) {
if (i >= start+3) {
isremove = true;
str = str.substr(0, start) + str.substr(i);
break;
}
start = i;
}
}
if (!isremove) {
break;
}
}
return str;
}
int findMinStep2(string board, string hand) {
sort(hand.begin(), hand.end());
int res = INT_MAX;
map<char, int> count;
for (char c : hand) count[c]++;
helper2(board, count, hand.size(), res, 0);
return res == INT_MAX ? -1 : res;
}
/**
* 大体上和上面的思想是类似的
*
* @param board
* @param count
* @param res
* @param idx
*/
void helper2(string board, map<char, int>& count, int numOfBalls, int& res, int cur) {
// 不可能存在小于0的情况,因为就是从1开始的,也不能消除次数大于手中的球的数量,说明没消除干净
if (res <= 0 || cur > numOfBalls) {
return ;
}
for (int i = 0; i < board.size(); ) {
// 存在不相等的情况,或者是board中只有一个元素的话,避免出现i+1越界,所以要写在前面
// 同时这里也说明如果存在连续相等的元素的话,那么其连续的最后一位的位置则为i,因为i+1就不再想等了
if (i < board.size()-1 && board[i] == board[i+1]) {
if (count[board[i]]) {
count[board[i]]--;
string new_board = board;
new_board.insert(new_board.begin() + i, board[i]);
new_board = nextStr(new_board);
if (new_board.size()) {
// 加一是因为已经使用了hand中的元素消除了一个,所以需要记录下来
helper2(new_board, count, numOfBalls, res, cur + 1);
} else {
res = min(res, cur + 1);
}
// 恢复
count[board[i]]++;
i++;
}
}
else {
if (count[board[i]] >= 2) {
count[board[i]] -= 2;
string new_board = board;
new_board.insert(new_board.begin() + i, board[i]);
new_board.insert(new_board.begin() + i, board[i]);
new_board = nextStr(new_board);
if (new_board.size()) {
// 加一是因为已经使用了hand中的元素消除了一个,所以需要记录下来
helper2(new_board, count, numOfBalls, res, cur + 2);
} else {
res = min(res, cur + 2);
}
// 恢复
count[board[i]] += 2;
}
}
i++;
}
}
/**
* 思想都是类似的,都是消除
*/
int helper3(string board, string hand) {
// 没有消除完
if (hand.size() == 0 && board.size() != 0) {
return MaxNum;
}
else if (board.size() == 0) {
return 0;
}
int res = MaxNum;
sort(hand.begin(), hand.end());
for (int i = 0; i < hand.size(); i++) {
// 不允许出现相等的
if (i > 0 && hand[i] == hand[i - 1]) {
continue;
}
// 生成新的字符串
string newhand = hand.substr(0, i) + hand.substr(i+1);
// 遍历
for (int j = 0; j < board.size(); j++) {
// 如果不能消除或者是前面的和后面的值相同,则继续
if (board[j] != hand[i] || (j > 0 && board[j] == board[j-1])) {
continue ;
}
int k = j;
// 统计相同的球的个数
while (k < board.size()-1 && board[k] == board[k+1]) {
k++;
}
//存在两个以上的元素
if (k - j >= 2) {
// 左右位置的下标
int l = j - 1, r = k;
while (l > 0 && r < board.size() && board[l] == board[r]) {
// 判断前后面是否还存在相等的元素,如果不存在则退出
if ((l > 0 && board[l - 1] == board[l]) || (r < board.size()-1 && board[r + 1] == board[r])) {
// 判断前面是否还存在相等的
while (l > 0 && board[l - 1] == board[l]) {
l--;
}
// 判断后面是否还存在相等的
while (r < board.size()-1 && board[r + 1] == board[r]) {
r++;
}
l--;
r++;
}
else {
break;
}
}
// 消除的结果
string newboard = board.substr(0, l + 1) + board.substr(r);
int nres = helper3(newboard, newhand);
res = min(res, nres + 1);
}
else {
// 没有什么可以消除的,往字符串中添加新元素
string newboard = board.substr(0, j) + hand[i] + board.substr(j);
int nres = helper3(newboard, newhand);
res = min(res, nres + 1);
}
}
}
return res;
}
/**
*
* @param board
* @param hand
* @return
*/
int findMinStep3(string board, string hand) {
int res = helper3(board, hand);
return res == MaxNum ? -1 : res;
}
void test() {
string board = "WRRBBW", hand = "RB";
cout << findMinStep3(board, hand) << endl;
// string result = board.substr(0, 3) + board.substr(6);
// board.erase(3, 3);
}
};
总结
我写了好几种方法,但是其实其的本质是类似的,你可以把它想象成将hand中的球作为起始结点,以board加入hand中的球后消除得到新的board作为下一步的扩展结点,board被消除完或者是没被消除完。
[LeetCode] Zuma Game 题解的更多相关文章
- [LeetCode] Zuma Game 祖玛游戏
Think about Zuma Game. You have a row of balls on the table, colored red(R), yellow(Y), blue(B), gre ...
- 「LeetCode」全部题解
花了将近 20 多天的业余时间,把 LeetCode 上面的题目做完了,毕竟还是针对面试的题目,代码量都不是特别大,难度和 OJ 上面也差了一大截. 关于二叉树和链表方面考察变成基本功的题目特别多,其 ...
- C#版 - Leetcode 65. 有效数字 - 题解
版权声明: 本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. Leetcod ...
- [LeetCode] Three Sum题解
Three Sum: Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? ...
- Leetcode的SQL题解:185. 部门工资前三高的员工
题目 查询部门工资前三高的员工. 我用的数据库是oracle. 下面是数据表的信息. Employee表数据: | ID | NAME | Salary | DepartmentId | | -- | ...
- LeetCode python实现题解(持续更新)
目录 LeetCode Python实现算法简介 0001 两数之和 0002 两数相加 0003 无重复字符的最长子串 0004 寻找两个有序数组的中位数 0005 最长回文子串 0006 Z字型变 ...
- 【LeetCode/LintCode】 题解丨字节跳动试题:第k大的子数组
给定一个长度为n的数组a,它有n(n+1)/2个子数组.请计算这些子数组的和,然后按照升序排列,并返回排序后第k个数. 1≤n≤10^5 1≤ai≤10^9 1≤k≤n(n+1)/2 在线 ...
- 【LeetCode/LintCode】 题解丨微软面试题:大楼轮廓
水平面上有 N 座大楼,每座大楼都是矩阵的形状,可以用一个三元组表示 (start, end, height),分别代表其在x轴上的起点,终点和高度.大楼之间从远处看可能会重叠,求出 N 座大楼的外轮 ...
- Leetcode 周赛#202 题解
本周的周赛题目质量不是很高,因此只给出最后两题题解(懒). 1552 两球之间的磁力 #二分答案 题目链接 题意 有n个空篮子,第i个篮子位置为position[i],现希望将m个球放到这些空篮子,使 ...
随机推荐
- enote笔记语言(3)(ver0.2)
what&why(why not)&how&when&where&which:紫色,象征着神秘而又潜蕴着强大的力量,故取紫色. key&keyword: ...
- apache的用户认证
1. 限制用户访问的方式: 1. 限制访问服务的客户端主机 2. 需要用户名和密码 2. 行为用户验证需要两步: 1. 创建一个包含用户名和密码的文件 2. 服务器上的哪些资源需要保护,哪些用户可以进 ...
- CI Weekly #14 | 如何搭建合适的持续交付开发流程?
时隔 10 个月,flow.ci 开始正式收费上线.为感谢对我们的内测支持,所有内测用户可继续免费使用基础版 30 天,截止至 3 月 15 日失效.欢迎随时告诉我们你对收费版 flow.ci 的反馈 ...
- [译]如何在Web开发中使用Python
[译]如何在Web开发中使用Python 原文:HOWTO Use Python in the Web 摘要 这篇文档展示了Python如何融入到web中.它介绍了几种Python结合web服务器的方 ...
- Windows Form线程同步
.Net多线程开发中,经常需要启动工作线程Worker thread处理某些事情,而工作线程中又需要更新主线程UI thread的界面状态.我们只能在主线程中操作界面控件,否则.Net会抛出异常. 那 ...
- 每天一个linux命令30)--chgrp命令
在Linux系统里,文件或目录的权限的掌控以拥有者及所属群组来管理.可以使用chgrp 指令取变更文件与目录所属群组,这种方式采用群组名称或群组识别码都可以. chgrp 命令就是change gr ...
- 每天一个Linux命令(17)--whereis命令
whereis 命令只能用于程序名的搜索,而且只搜索二进制文件(参数-b).man说明文件(参数-m)和源代码文件(参数-s).如果省略参数,则返所有信息. 和find相比,whereis查找的速度非 ...
- 第十四篇 SQL游标、函数的使用方法
游标的的使用有日常的开发和维护的过程不使用的并不多,但是碰到一些棘手的问题的时候,游标时常是个非常好的帮手,下面就说下游标的使用方法,方法自己以后查阅,和加深一些印象,下面以一个存储过程为例 ...
- Web前端与移动开发学习路线图
文章转载自「开发者圆桌」一个关于开发者入门.进阶.踩坑的微信公众号 这里整理的Web前端与移动开发学习路线图包含初中级两个部分,你可以通过百度云盘下载观看对应的视频 链接: http://pan.ba ...
- Struts文件下载
/* 文件下载的先决条件 * 1. 在xml配置文件中必须配置一个type="stream"的result, result中不需要填写任何内容 * 2. 在Action中编写一个接 ...