题目

题目

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:same_tree题解

    一.     题目: 给定两个二叉树,编写一个函数来检查它们是否相等或为空树.假设两个二叉树被觉得是相等的,那么它们在结构上是同样的,而且随意节点具有同样的值. 二.     分析 非常easy的题目 ...

  8. [LeetCode] Is Subsequence 题解

    前言 这道题的实现方法有很多,包括dp,贪心算法,二分搜索,普通实现等等. 题目 Given a string s and a string t, check if s is subsequence ...

  9. [LeetCode] 01 Matrix 题解

    题意 # 思路 我一开始的时候想的是嘴 # 实现 ```cpp // // include "../PreLoad.h" class Solution { public: /** ...

随机推荐

  1. mysql更新密码

    mysql -u root mysql> use mysql; mysql> UPDATE user SET Password = PASSWORD('newpass') WHERE us ...

  2. Eclipse解决Ctrl+c很卡的方法

    问题如下 : 每当在eclipse中开发java项目打开jsp页面编辑的时候,按了ctrl+c就会卡死几秒的状态,一天经常这样会让人非常的烦躁. 解决方法如下: Eclipse -- Windows- ...

  3. angular的路由

    AngularJS 路由允许我们通过不同的 URL 访问不同的内容. 通过 AngularJS 可以实现多视图的单页Web应用(single page web application,SPA). 下面 ...

  4. UDP SOCKET网络通信 C#

    接收端 using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Thread ...

  5. Laravel 之Service Providers

    Service providers are the central place of all Laravel application bootstrapping. Your own applicati ...

  6. nginx服务器是怎么执行php脚本的?

    简单的说: fastCGI是nginx和php之间的一个通信接口,该接口实际处理过程通过启动php-fpm进程来解 析php脚本,即php-fpm相 当于一个动态应用服务器,从而实现nginx动态解析 ...

  7. WebDriverExtensionsByC#

    测试工具//********************************************************************************************** ...

  8. C++向量(08)

    在数组生存期内,数组的大小是不会改变的.向量是一维数组的类版本,它与数组相似,其中的元素项总是连续存储的,但它和数组不同的是:向量中存储元素的多少可以在运行中根据需要动态地增长或缩小.向量是类模板,具 ...

  9. Java基础_0306:数组的定义与使用

    数组 数组指的就是一组相关变量的集合.例如:如果说现在要想定义100个整型变量,按照传统的思路,可能这样定义: int i1,i2 ,... i100,一共写100个变量. 以上的形式的确可以满足技术 ...

  10. iview 刷新滞后于html问题

    一.问题描述 每次刷新页面,下面的内容就会一闪而过. 一闪而过后恢复正常: 二.解决 问题代码: @*<span>修改密码</span>*@ @*<span>{{m ...