题目

题目

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 题解的更多相关文章

  1. [LeetCode] Zuma Game 祖玛游戏

    Think about Zuma Game. You have a row of balls on the table, colored red(R), yellow(Y), blue(B), gre ...

  2. 「LeetCode」全部题解

    花了将近 20 多天的业余时间,把 LeetCode 上面的题目做完了,毕竟还是针对面试的题目,代码量都不是特别大,难度和 OJ 上面也差了一大截. 关于二叉树和链表方面考察变成基本功的题目特别多,其 ...

  3. C#版 - Leetcode 65. 有效数字 - 题解

    版权声明: 本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. Leetcod ...

  4. [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? ...

  5. Leetcode的SQL题解:185. 部门工资前三高的员工

    题目 查询部门工资前三高的员工. 我用的数据库是oracle. 下面是数据表的信息. Employee表数据: | ID | NAME | Salary | DepartmentId | | -- | ...

  6. LeetCode python实现题解(持续更新)

    目录 LeetCode Python实现算法简介 0001 两数之和 0002 两数相加 0003 无重复字符的最长子串 0004 寻找两个有序数组的中位数 0005 最长回文子串 0006 Z字型变 ...

  7. 【LeetCode/LintCode】 题解丨字节跳动试题:第k大的子数组

    给定一个长度为n的数组a,它有n(n+1)/2​​个子数组.请计算这些子数组的和,然后按照升序排列,并返回排序后第k个数. 1≤n≤10​^5 1≤a​i≤10^​9 1≤k≤​n(n+1)/2 在线 ...

  8. 【LeetCode/LintCode】 题解丨微软面试题:大楼轮廓

    水平面上有 N 座大楼,每座大楼都是矩阵的形状,可以用一个三元组表示 (start, end, height),分别代表其在x轴上的起点,终点和高度.大楼之间从远处看可能会重叠,求出 N 座大楼的外轮 ...

  9. Leetcode 周赛#202 题解

    本周的周赛题目质量不是很高,因此只给出最后两题题解(懒). 1552 两球之间的磁力 #二分答案 题目链接 题意 有n个空篮子,第i个篮子位置为position[i],现希望将m个球放到这些空篮子,使 ...

随机推荐

  1. docker - 容器里安装mysql

    在docker中安装mysql ubuntu官方镜像是精简的ubuntu系统,很多软件和库没有安装,所以直接安装mysql的话依赖较多,建议直接从源码编译安装mysql 通过命令行安装 先启动一个容器 ...

  2. C#Redis 主从复制

    一.前戏 下面的列表清楚的解释了Redis Replication的特点和优势.    1). 同一个Master可以同步多个Slaves.    2). Slave同样可以接受其它Slaves的连接 ...

  3. MongoDB的安装及恢复

    在http://www.mongodb.org/display/DOCS/Downloads 下载对应版本 mongodb 安装数据库 解压文档,复制到c盘,改名为mongodb 新建文件夹c:/da ...

  4. 理解margin负值

    效果 上和左方的margin负值使元素向上和左方向移动,如果该元素position不是absolute或fixed,这还会导致之后的元素也向上,左移 下和右方的margin负值会缩小下和右方的空间,使 ...

  5. 《Django By Example》第八章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:还有4章!还有4章全书就翻译完成了 ...

  6. 腾讯云分布式高可靠消息队列服务CMQ架构

    在分布式大行其道的今天,我们在系统内部.平台之间广泛运用消息中间件进行数据交换及解耦.CMQ是腾讯云内部自研基于的高可靠.强一致.可扩展分布式消息队列,在腾讯内部包括微信手机QQ业务红包.腾讯话费充值 ...

  7. CSS知识点汇总 (全是干货O(∩_∩)O~ )

    一.CSS选择器 [选择器的命名规则] 1.只能有字母数字下划线组成,不能有其他任何特殊字符 2.开头不能是数字 [通用选择器]1.写法:*{}2.作用:选中页面中的所有标签(大范围修改)3.优先级: ...

  8. &&运算符,三木运算符与React的条件渲染

    在使用react框架的时候中往往会遇到需要条件渲染的情形,这时候,许多人会设想采用if语句来实现,比如下面,当满足条件condition时,conditonRender渲染组件ComponentA,当 ...

  9. 大数据系列之Flume--几种不同的Sources

    1.flume概念 flume是分布式的,可靠的,高可用的,用于对不同来源的大量的日志数据进行有效收集.聚集和移动,并以集中式的数据存储的系统. flume目前是apache的一个顶级项目. flum ...

  10. struts2(一) struts2入门

    首先推荐一本书,虽然我还没看过,但是我以后肯定会看的,<Struts+技术内幕>提取密码:kg6w .现在只是停留在会使用struts2的层次,自己也想继续深入研究,但是感觉自己的知识面还 ...