1034. 边框着色(Python)

难度:★★★☆☆
类型:数组
方法:深度优先搜索,宽度优先搜索

题目

力扣链接请移步本题传送门
更多力扣中等题的解决方案请移步力扣中等题目录

给出一个二维整数网格 grid,网格中的每个值表示该位置处的网格块的颜色。

只有当两个网格块的颜色相同,而且在四个方向中任意一个方向上相邻时,它们属于同一连通分量。

连通分量的边界是指连通分量中的所有与不在分量中的正方形相邻(四个方向上)的所有正方形,或者在网格的边界上(第一行/列或最后一行/列)的所有正方形。

给出位于 (r0, c0) 的网格块和颜色 color,使用指定颜色 color 为所给网格块的连通分量的边界进行着色,并返回最终的网格 grid 。

示例 1:

输入:grid = [[1,1],[1,2]], r0 = 0, c0 = 0, color = 3
输出:[[3, 3], [3, 2]]

示例 2:

输入:grid = [[1,2,2],[2,3,2]], r0 = 0, c0 = 1, color = 3
输出:[[1, 3, 3], [2, 3, 3]]

示例 3:

输入:grid = [[1,1,1],[1,1,1],[1,1,1]], r0 = 1, c0 = 1, color = 2
输出:[[2, 2, 2], [2, 1, 2], [2, 2, 2]]

提示:

1 <= grid.length <= 50
1 <= grid[0].length <= 50
1 <= grid[i][j] <= 1000
0 <= r0 < grid.length
0 <= c0 < grid[0].length
1 <= color <= 1000

解答

画图软件读者应该熟悉吧,可以尝试里面的颜料桶操作,把一个连通域换成另一个颜色,但是如果本题仅仅是实现这个功能,就简单了,本题不仅需要找到连通域,而且还要分类联通域中每个点是否属于边界点,仅把边界点进行着色。

我们给出一些定义,把选定点 (r0, c0) 作为起始点,将该点所在联通域作为选定区域,该区域中边界上的点作是着色点。

着色点需要满足以下任意一个条件:
第一,该点在选定区域内,并且该点位于整个方格的边框上;
第二,该点在选定区域内,并且该点周围四个点中,有任意一个点的颜色与该点不同。

一个简单的做法是,我们通过深度优先搜索得到选定区域中的每个点,然后根据上述原则选出来选定区域中的边界点,并对其进行着色。

class Solution:
    def colorBorder(self, grid, r0, c0, color):
        self.grid = [[c for c in row] for row in grid]
        self.rows = len(grid)
        self.columns = len(grid[0])
        self.area = [[False for _ in range(self.columns)] for _ in range(self.rows)]
        self.prev_color = grid[r0][c0]
        self.new_color = color

        def is_border(r, c):
            if r == 0 or r == self.rows - 1:
                return True
            if c == 0 or c == self.columns - 1:
                return True
            return not all(grid[r][c] == grid[nr][nc] for nr, nc in get_neighbors(r, c))

        def get_neighbors(r, c):
            for nr, nc in [(r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)]:
                if 0 <= nr < self.rows and 0 <= nc < self.columns:
                    yield nr, nc

        def dfs(r, c):
            if not self.area[r][c] and self.grid[r][c] == self.prev_color:
                self.area[r][c] = True
                for nr, nc in get_neighbors(r, c):
                    dfs(nr, nc)

        def color_grid():
            for r in range(self.rows):
                for c in range(self.columns):
                    if self.area[r][c] and is_border(r, c):
                        self.grid[r][c] = self.new_color

        dfs(r0, c0)
        color_grid()
        return self.grid


s = Solution()
grid = [[1,2,2],
        [2,3,2]]
print(s.colorBorder(grid, 0, 1, 3))

grid = [[1,1,1],
        [1,1,1],
        [1,1,1]]
print(s.colorBorder(grid, 1, 1, 2))

为了便于理解,以上代码都写成了函数块的方式,当然,可以在代码上做一些简化,尤其要注意逻辑上的判断条件:

from typing import List
class Solution:
    def colorBorder(self, grid: List[List[int]], r0: int, c0: int, color: int) -> List[List[int]]:
        if not grid:
            return []
        pos = [(-1, 0), (1, 0), (0, -1), (0, 1)]
        m, n = len(grid), len(grid[0])
        visited = {(r0, c0)}
        target = grid[r0][c0]

        def dfs(r, c):
            for dr, dc in pos:
                nr = r + dr
                nc = c + dc
                if 0 <= nr < m and 0 <= nc < n:
                    if (nr, nc) not in visited:
                        if grid[nr][nc] == target:
                            visited.add((nr, nc))
                            dfs(nr, nc)
                        else:
                            grid[r][c] = color
                else:
                    grid[r][c] = color

        dfs(r0, c0)
        return grid

或者使用宽度优先搜索算法实现,算法流程和上面是一样的,仅仅把递归换成了队列:

from typing import List
class Solution:
    def colorBorder(self, grid: List[List[int]], r0: int, c0: int, color: int) -> List[List[int]]:
        if not grid:
            return []
        pos = [(-1, 0), (1, 0), (0, -1), (0, 1)]
        rows, columns = len(grid), len(grid[0])
        queue = [(r0, c0)]
        visited = {(r0, c0)}
        target = grid[r0][c0]

        while queue:
            r, c = queue.pop(0)
            for dr, dc in pos:
                nr = r + dr
                nc = c + dc
                if 0 <= nr < rows and 0 <= nc < columns:
                    if (nr, nc) not in visited:
                        if grid[nr][nc] == target:
                            visited.add((nr, nc))
                            queue.append((nr, nc))
                        else:
                            grid[r][c] = color
                else:
                    grid[r][c] = color

        return grid

如有疑问或建议,欢迎评论区留言~

有关更多力扣中等题的python解决方案,请移步力扣中等题解析

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

推荐阅读更多精彩内容