Python玩转算法—扫雷

此题来自LeetCode上的一道难度为Medium的题,说是有一张玩到一半的扫雷地图,接下来给你指定一个点击位置,让你预测点击之后,地图将发生怎么样的变化。看到这道题,瞬间让我想起了以前玩扫雷的日子,可惜Mac上没有自带扫雷,与是我又去AppStore上下载了扫雷,重新把玩了一番,经典游戏就是这样,百玩不厌。

经典扫雷游戏

题目中,我们用'E'代表未探索的,而且没有雷的点, 用'M'代表有雷的位置, 用'B'代表探索过,而且周围8个邻居点都没有雷的位置,如果某个位置已经探索过,但是周围有雷,用数字代表周围的雷的个数。

游戏的规则很简单,当我们点击一个未探索的位置时,如果

  1. 当前位置为M, 则扫到雷,将其置为X, 游戏结束
  2. 当前位置E,则将其置为B,然后继续递归处理其周围未探索的位置
  3. 当前位置为E,而且周围有雷,则用周围雷的个数替换
  4. 如果不能探索更多的位置,则返回

比如
Input:
[['E', 'E', 'E', 'E', 'E'],
['E', 'E', 'M', 'E', 'E'],
['E', 'E', 'E', 'E', 'E'],
['E', 'E', 'E', 'E', 'E']]

Click : [3,0]

Output:

[['B', '1', 'E', '1', 'B'],
['B', '1', 'M', '1', 'B'],
['B', '1', '1', '1', 'B'],
['B', 'B', 'B', 'B', 'B']]

Explanation:

因为扫雷的地图本身就是一张图,我们很容易想到能不能用图的遍历算法去解决问题,我们可以先试试深度优先遍历DFS

        def updateBoard(self, board, click):
    
        M, N = len(board), len(board[0])
        dirs = [[0, 1], [0, -1], [1, 0], [-1, 0], [-1, -1], [-1, 1], [1, -1], [1, 1]]
        def isInRange(x, y):
            return 0 <= x < M and 0 <= y < N
        
        def dfs(board, x, y):
            if board[x][y] == 'M':
                board[x][y] = 'X'
                return
            # 获取周围雷的个数
            mineCnt = sum(1 if isInRange(x + dir[0], y + dir[1]) and board[x + dir[0]][y + dir[1]] == 'M'
                          else 0 for dir in dirs)
            if mineCnt != 0:
                board[x][y] = str(mineCnt)
            else:
                
                board[x][y] = 'B'
                # 获取周围所有为探索且没有雷的位置
                eArr = [(x + dir[0], y + dir[1]) for dir in dirs if isInRange(x + dir[0], y + dir[1])
                        and board[x + dir[0]][y + dir[1]] == 'E']
                for xx, yy in eArr:
                    #递归处理邻居位置
                    dfs(board, xx, yy)

        dfs(board, click[0], click[1])
        return board

一般我们在DFS中需要

  1. 维持一个已访问位置的标记集合,这里我们并不需要,因为只要目标位置不为B就表示我们未访问过
  2. 在递归访问的过程中,我们只有当周围没有雷的时候,才会去递归访问邻居位置,否则视为已经到dfs的叶子,递归返回

我们也可以使用BFS来做这个遍历处理:


    def updateBoard2(self, board, click):
        M, N = len(board), len(board[0])
        def isInRange(x, y):
            return 0 <= x < M and 0 <= y < N

        queue = []
        dirs = [[0, 1], [0, -1], [1, 0], [-1, 0], [-1, -1], [-1, 1], [1, -1], [1, 1]]
        queue.append(click)
        while len(queue) > 0:
            x, y = queue.pop(0)
            if board[x][y] == 'M':
                board[x][y] = 'X'
                continue

            mineCnt = sum(1 if isInRange(x + dir[0], y + dir[1]) and board[x + dir[0]][y + dir[1]] == 'M'
                          else 0 for dir in dirs)
            
            if mineCnt == 0:
                board[x][y] = 'B'
                for dir in dirs:
                    xx, yy = x + dir[0], y + dir[1]
                    if isInRange(xx,yy) and board[xx][yy] == 'E':
                        # 这一步非常重要,避免重复加入队列
                        board[xx][yy] = 'B'
                        queue.append((xx, yy))
                        
            else:
                board[x][y] = str(mineCnt)
        return board

采用一个队列,每次将同一距离的点加入队列,同样只有当前位置的周围没有雷的时候,才会将没有访问过的邻居位置加入队列。

Python语言越来越发挥重要的作用,尤其是在如今这个AI炙手可热的年代,不管我们在从事什么平台的开发,多学一点python对我们肯定有好处。Python玩转算法这个系列就是围绕python展开,用python去解决一些问题,实现一些算法。如果有读者对python也感兴趣,却找不到合适的资料去学习,不妨跟随这个系列一起学习,欢迎各位读者关注和转发~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容