This question is about implementing a basic elimination algorithm for Candy Crush.

Given a 2D integer array board representing the grid of candy, different positive integers board[i][j] represent different types of candies. A value of board[i][j] = 0 represents that the cell at position (i, j) is empty. The given board represents the state of the game following the player's move. Now, you need to restore the board to a stable state by crushing candies according to the following rules:

  1. If three or more candies of the same type are adjacent vertically or horizontally, "crush" them all at the same time - these positions become empty.
  2. After crushing all candies simultaneously, if an empty space on the board has candies on top of itself, then these candies will drop until they hit a candy or bottom at the same time. (No new candies will drop outside the top boundary.)
  3. After the above steps, there may exist more candies that can be crushed. If so, you need to repeat the above steps.
  4. If there does not exist more candies that can be crushed (ie. the board is stable), then return the current board.

You need to perform the above rules until the board becomes stable, then return the current board.

Example 1:

Input:
board =
[[110,5,112,113,114],[210,211,5,213,214],[310,311,3,313,314],[410,411,412,5,414],[5,1,512,3,3],[610,4,1,613,614],[710,1,2,713,714],[810,1,2,1,1],[1,1,2,2,2],[4,1,4,4,1014]]
Output:
[[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[110,0,0,0,114],[210,0,0,0,214],[310,0,0,113,314],[410,0,0,213,414],[610,211,112,313,614],[710,311,412,613,714],[810,411,512,713,1014]]
Explanation:

Note:

  1. The length of board will be in the range [3, 50].
  2. The length of board[i] will be in the range [3, 50].
  3. Each board[i][j] will initially start as an integer in the range [1, 2000].

这道题就是糖果消消乐,博主刚开始做的时候,没有看清楚题意,以为就像游戏中的那样,每次只能点击一个地方,然后消除后糖果落下,这样会导致一个问题,就是原本其他可以消除的地方在糖果落下后可能就没有了,所以博主在想点击的顺序肯定会影响最终的 stable 的状态,可是题目怎么没有要求返回所剩糖果最少的状态?后来发现,其实这道题一次消除 table 中所有可消除的糖果,然后才下落,形成新的 table,这样消除后得到的结果就是统一的了,这样也大大的降低了难度。下面就来看如何找到要消除的糖果,可能有人会觉得像之前的岛屿的题目一样找连通区域,可是这道题的有限制条件,只有横向或竖向相同的糖果数达到三个才能消除,并不是所有的连通区域都能消除,所以找连通区域不是一个好办法。最好的办法其实是每个糖果单独检查其是否能被消除,然后把所有能被删除的糖果都标记出来统一删除,然后在下落糖果,然后再次查找,直到无法找出能够消除的糖果时达到稳定状态。好,用一个数组来保存可以被消除的糖果的位置坐标,判断某个位置上的糖果能否被消除的方法就是检查其横向和纵向的最大相同糖果的个数,只要有一个方向达到三个了,当前糖果就可以被消除。所以对当前糖果的上下左右四个方向进行查看,用四个变量 x0, x1, y0, y1,其中 x0 表示上方相同的糖果的最大位置,x1 表示下方相同糖果的最大位置,y0 表示左边相同糖果的最大位置,y1 表示右边相同糖果的最大位置,均初始化为当前糖果的位置,然后使用 while 循环向每个方向遍历,注意并不需要遍历到尽头,而是只要遍历三个糖果就行了,因为一旦查到了三个相同的,就说明当前的糖果已经可以消除了,没必要再往下查了。查的过程还要注意处理越界情况,好,得到了上下左右的最大的位置,分别让相同方向的做差,如果水平和竖直方向任意一个大于3了,就说明可以消除,将坐标加入数组 del 中。注意这里一定要大于3,是因为当发现不相等退出 while 循环时,坐标值已经改变了,所以已经多加了或者减了一个,所以差值要大于3。遍历完成后,如果数组 del 为空,说明已经 stable 了,直接 break 掉,否则将要消除的糖果位置都标记为0,然后进行下落处理。下落处理实际上是把数组中的0都移动到开头,那么就从数组的末尾开始遍历,用一个变量t先指向末尾,然后然后当遇到非0的数,就将其和t位置上的数置换,然后t自减1,这样t一路减下来都是非0的数,而0都被置换到数组开头了,参见代码如下:

class Solution {
public:
vector<vector<int>> candyCrush(vector<vector<int>>& board) {
int m = board.size(), n = board[].size();
while (true) {
vector<pair<int, int>> del;
for (int i = ; i < m; ++i) {
for (int j = ; j < n; ++j) {
if (board[i][j] == ) continue;
int x0 = i, x1 = i, y0 = j, y1 = j;
while (x0 >= && x0 > i - && board[x0][j] == board[i][j]) --x0;
while (x1 < m && x1 < i + && board[x1][j] == board[i][j]) ++x1;
while (y0 >= && y0 > j - && board[i][y0] == board[i][j]) --y0;
while (y1 < n && y1 < j + && board[i][y1] == board[i][j]) ++y1;
if (x1 - x0 > || y1 - y0 > ) del.push_back({i, j});
}
}
if (del.empty()) break;
for (auto a : del) board[a.first][a.second] = ;
for (int j = ; j < n; ++j) {
int t = m - ;
for (int i = m - ; i >= ; --i) {
if (board[i][j]) swap(board[t--][j], board[i][j]);
}
}
}
return board;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/723

参考资料:

https://leetcode.com/problems/candy-crush/

https://leetcode.com/problems/candy-crush/discuss/178366/Another-Java-Solution

https://leetcode.com/problems/candy-crush/discuss/109225/Simple-C%2B%2B-brute-force

https://leetcode.com/problems/candy-crush/discuss/113914/15-ms-Short-Java-Solution-Mark-crush-with-negative-value

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Candy Crush 糖果消消乐的更多相关文章

  1. [LeetCode] Candy (分糖果),时间复杂度O(n),空间复杂度为O(1),且只需遍历一次的实现

    [LeetCode] Candy (分糖果),时间复杂度O(n),空间复杂度为O(1),且只需遍历一次的实现 原题: There are N children standing in a line. ...

  2. [LeetCode] 723. Candy Crush 糖果消消乐

    This question is about implementing a basic elimination algorithm for Candy Crush. Given a 2D intege ...

  3. [LeetCode] 723. Candy Crush 糖果粉碎

    This question is about implementing a basic elimination algorithm for Candy Crush. Given a 2D intege ...

  4. [LeetCode] Candy 分糖果问题

    There are N children standing in a line. Each child is assigned a rating value. You are giving candi ...

  5. 消消乐、candy crush类三消游戏程序逻辑分析

    最近在开发一款类似消消乐的三消游戏,在碰到实现斜方向下落的时候卡住了很长时间.好几天没有思路,原本的思路是一次性预判多个宝石的一连串运动路径,运用缓动运动队列来实现宝石运动路径,例如 下落->滑 ...

  6. 【LeetCode】723. Candy Crush 解题报告 (C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 暴力 日期 题目地址:https://leetcode ...

  7. net.sz.framework 框架 ORM 消消乐超过亿条数据排行榜分析 天王盖地虎

    序言 天王盖地虎, 老婆马上生孩子了,在家待产,老婆喜欢玩消消乐类似的休闲游戏,闲置状态,无聊的分析一下消消乐游戏的一些技术问题: 由于我主要是服务器研发,客户端属于半吊子,所以就分析一下消消乐排行榜 ...

  8. RSP小组——消消乐

    RSP小组--消消乐 团队所有博客总结 1.团队第一周作业 2.团队第二周作业 3.RSP小组--团队冲刺博客一 4.RSP小组--团队冲刺博客二 5.RSP小组--团队冲刺博客三 6.RSP小组-- ...

  9. PHP实现开心消消乐的算法示例

    本文主要介绍了关于PHP如何实现我们大家都知道的开心消消乐的算法,分享PHP教程出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 一.需求描述:      1.在一个8*8的矩阵方格中随机 ...

随机推荐

  1. 解决数据库mysql插入乱码问题

    当我们遇到mysql乱码问题的时候,一般要修改my.ini文件: 我遇到的是两个版本,一个是mysql5.5版本,另一个是mysql5.7 5.5的是在这个目录下面:C:\Program Files\ ...

  2. python全栈学习--day2

    一.in的使用 说明:in有相当多的用处,比如判断,循环for 等. 实例一:in 操作符用于判断关键字是否存在于变量中 s = '男人john' print('男孩' in s) print('男孩 ...

  3. 铜齿铁牙UP计划

    铜齿铁牙UP计划 我在""做教练"之好声音训练"给出了老师.播音主持学习者,声乐学习者科学用声三要点: 用气发声 共鸣发声 虚实结合 用气发声首先要学会腹式呼吸 ...

  4. Beta冲刺第七天

    一.昨天的困难 没有困难. 二.今天进度 1.林洋洋:MD图片上传,修复权限问题,修复本地存储判空问题,修复协作申请没有过滤问题. 2.黄腾达:添加文件链接和邀请链接复制功能,协作树界面优化. 3.张 ...

  5. C语言--总结报告

    1.当初你是如何做出选择计算机专业的决定的? 经过一个学期,你的看法改变了么,为什么? 你觉得计算机是你喜欢的领域吗,它是你擅长的领域吗? 为什么? 当初填报志愿我是有很明确的专业方向的,就是IT类的 ...

  6. Android开发简易教程

    Android开发简易教程 Android 开发因为涉及到代码编辑.UI 布局.打包等工序,有一款好用的IDE非常重要.Google 最早提供了基于 Eclipse 的 ADT 作为开发工具,后来在2 ...

  7. scrapy 模拟登陆

    import scrapy import urllib.request from scrapy.http import Request,FormRequest class LoginspdSpider ...

  8. 微信小程序轮播图

    swiper标签 <!--index.wxml--> <swiper class="swiper" indicator-dots="true" ...

  9. Microsoft dynamic sdk中join应该注意的问题.

    QueryExpression queryNextSeq = new QueryExpression { EntityName = "ep_prodoperationsequence&quo ...

  10. php析构方法

    析构方法说明: 1. 析构方法会自动调用 2. 析构方法主要用于销毁资源(比如释放数据库的链接,图片资源...销毁某个对象..); 析构函数会在到对象的所有的引用都被删除或者当对象被显示销毁时执行. ...