[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个球放到这些空篮子,使 ...
随机推荐
- Azure 基础:用 PowerShell 自动发布 CloudServices
在软件的开发过程中,自动化的编译和部署能够带来很多的优势.下面我们聊聊如何自动发布云应用程序到 azure 上的 cloud services. 打包要发布的内容 首先使用 msbuild 编译 *. ...
- Android 调用jepg库进行图片压缩,保持图片不失真
1. 浅谈为什么Android和iOS图片质量差距那么大? 首先来说,作为一个安卓狗,机器当然用的是安卓的手机.现在的安卓手机大多数都会以高清拍照,动不动就几千万柔光相机来吸引各种买家.买来后,拍照发 ...
- WEB中调用Nutch执行JOB抓取
参考:在Eclipse中运行Nutch 把nutch的源代码导入到eclipse工程自定义抓取任务. 下载源码: http://svn.apache.org/repos/asf/nutch/ 从svn ...
- ARP攻击
ARP攻击,是针对以太网地址解析协议(ARP)的一种攻击技术,就是通过伪造IP地址和MAC地址实现ARP欺骗,能够在网络中产生大量的ARP通信量使网络阻塞.此种攻击可让攻击者取得局域网上的数据封包甚至 ...
- BASH SHELL not a valid identifier
解决BASH SHELL脚本报错 ‘: not a valid identifier当在shell编辑脚本时,运行时出现了" ‘: not a valid identifier " ...
- [编织消息框架][设计协议]优化long,int转换
理论部分 一个long占8byte,大多数应用业数值不超过int每次传输多4byte会很浪费 有没有什么办法可以压缩long或int呢? 答案是有的,原理好简单,如果数值不超过int.max_valu ...
- .NET中的repeater简介及分页效果
Repeater控件是一个数据绑定容器控件,它能够生成各个项的列表,并可以使用模板定义网页上各个项的布局.当该页运行时,该控件为数据源中的每个项重复此布局. 配合模板使用repeater控件 若要使 ...
- AR入门系列-07-Vuforia柱形体识别
今天为大家带来Vuforia柱形体识别的使用教程 首先我们要进入Vuforia官网在TargetManager中添加Target,这次我们添加的类型为Cylinder圆柱 Bottom Diamete ...
- ACM 子串和
子串和 时间限制:5000 ms | 内存限制:65535 KB 难度:3 描述 给定一整型数列{a1,a2...,an},找出连续非空子串{ax,ax+1,...,ay},使得该子序列的和最 ...
- Bzoj超级经验大放送题集(好评如潮哦~~~)
其实这些是因为没有数据才形成的...唯一可惜的是这些都是需要300软妹币才能打开的萌萌哒权限题*^_^* 好啦,吾来教你如何快速AC么么哒 pascal: 1 begin end. //Pascal ...