1042. 不临接植花(Python)

难度:★★★☆☆
类型:图
方法:贪心

题目

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

有 n 个花园,按从 1 到 n 标记。另有数组 paths ,其中 paths[i] = [xi, yi] 描述了花园 xi 到花园 yi 的双向路径。在每个花园中,你打算种下四种花之一。

另外,所有花园 最多 有 3 条路径可以进入或离开.

你需要为每个花园选择一种花,使得通过路径相连的任何两个花园中的花的种类互不相同。

以数组形式返回 任一 可行的方案作为答案 answer,其中 answer[i] 为在第 (i+1) 个花园中种植的花的种类。花的种类用 1、2、3、4 表示。保证存在答案。

示例 1:

输入:n = 3, paths = [[1,2],[2,3],[3,1]]
输出:[1,2,3]
解释:
花园 1 和 2 花的种类不同。
花园 2 和 3 花的种类不同。
花园 3 和 1 花的种类不同。
因此,[1,2,3] 是一个满足题意的答案。其他满足题意的答案有 [1,2,4]、[1,4,2] 和 [3,2,1]

示例 2:

输入:n = 4, paths = [[1,2],[3,4]]
输出:[1,2,1,2]

示例 3:

输入:n = 4, paths = [[1,2],[2,3],[3,4],[4,1],[1,3],[2,4]]
输出:[1,2,3,4]

提示:

1 <= n <= 104
0 <= paths.length <= 2 * 104
paths[i].length == 2
1 <= xi, yi <= n
xi != yi
每个花园 最多 有 3 条路径可以进入或离开

解答

我们把花园看成结点,联系各个结点的路径用数组集合的方式给出,很容易想到用深度优先搜索或宽度优先搜索的方法探索连通域。

解法1:深度优先搜索

第一步,建图。

为了便于表达,我们把用字典的形式存储每个结点的临近结点。这里需要注意的是,为了便于python索引,我们把每个花园编号减1,将1到n范围转到了0到n-1范围。graph[node]是一个列表,里面是与node结点相邻的所有结点。

第二步,染色列表。

为了存储每个花园的染色结果,我们准备一个列表color_of_,color_of_[node]表示node结点被染色的结果,列表长度为n,默认值为0,每个位置将要被染色成1,2,3,4中的一个。

第三步,深度优先搜索。

定义深度优先搜索函数实现循环染色。函数有两个输入,一个是结点node,一个是该结点需要被染色的结果color,函数返回值是布尔量,表达能否成功染色。函数过程中执行染色操作。

入口处需要优先判断是否能被染色,遍历node的每个相邻结点,如果发现任何一个相邻结点已经被染色为color,则染色失败,直接返回False。

如果通过了上面的校验,则可以将该结点染色,color_of_[node] = color,接下来就是把node的临近结点neighbor染色,这里需要注意颜色的选择。我们需要选择除了color以外的所有颜色,将这些颜色分别做尝试,一旦尝试成功,则不再进行其他颜色的尝试。临近结点neighbor的选择也有讲究,如果该节点已经被染了色,也就是该节点处color_of_对应位置处的值不是零,该节点是不需要再考虑的。如果所有临近结点都完成染色,则dfs返回值记得设置为True,代表node结点染色成功。

第四步,遍历。

接下来就是使用dfs函数的时候。我们有必要遍历每一个结点,一旦某结点没有被染色(通过color_of_[node] 是否为零判断),则调用dfs函数进行染色,颜色的选择与上面类似,需要进行尝试。

题目的解答过程实际上就是color_of_的填充过程,所有结点遍历完成后,如果发现color_of_中还有没有被染色的结点,也就是0 in color_of_,则说明无法完成所有结点的染色,否则,直接返回染色结果。

编程中其他注意事项:

第一,为了给字典提供默认值,我们使用defaultdict类;

第二,dfs函数的设计过程中,需要将终止条件写在开头。

from collections import defaultdict


class Solution:
    def gardenNoAdj(self, n, paths):
        graph = defaultdict(set)
        for u, v in paths:
            u, v = u - 1, v - 1
            graph[u].add(v)
            graph[v].add(u)

        color_of_ = [0] * n
        colors = {1, 2, 3, 4}

        def dfs(node, color):
            for neighbor in graph[node]:
                if color_of_[neighbor] == color:
                    return False
            color_of_[node] = color

            for color in colors - {color}:
                for neighbor in graph[node]:
                    if color_of_[neighbor] == 0 and dfs(neighbor, color):
                        return True
            return True

        for node in range(n):
            if color_of_[node] == 0:
                for color in colors:
                    if dfs(node, color):
                        break

        if 0 in color_of_:
            return "Unable for color!"
        return color_of_


s = Solution()
print(s.gardenNoAdj(3, [[1,2],[2,3],[3,1]]))
print(s.gardenNoAdj(4,  [[1,2],[3,4]]))
print(s.gardenNoAdj(4, [[1,2],[2,3],[3,4],[4,1],[1,3],[2,4]]))
print(s.gardenNoAdj(5, [[1, 2], [1, 3], [1, 4], [1, 5],
                        [2, 3], [2, 4], [2, 5],
                        [3, 4], [3, 5],
                        [4, 5],
                        ]))

解法2:贪心

因为题目已经告诉了我们,染色是一定可以成功的,我们就可以直接放心的填充每一个结点了。最关键的填充什么颜色。对于某一个结点node,其颜色需要根据临近结点填充,而且有的临近结点已经被填充过了,有的没有,我们只需要考虑被填充过的那些就好,需要保证该结点的颜色与那些已经被填充过的结点颜色都不同,至于到底填什么颜色,随便弹出一个满足条件的就够了。只要每填充一个结点,都按照上面的法则,则填充结果一定是满足要求的。这样在写法上是非常简单的。

python里通过集合相减的操作实现剩余颜色的获取。

from collections import defaultdict
from typing import List


class Solution:
    def gardenNoAdj(self, n: int, paths: List[List[int]]) -> List[int]:
        graph = defaultdict(list)
        for u, v in paths:
            u, v = u - 1, v - 1
            graph[u].append(v)
            graph[v].append(u)
        ans = [0] * n
        for u in range(n):
            colors = {1, 2, 3, 4} - set(ans[v] for v in graph[u])
            ans[u] = colors.pop()
        return ans

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

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

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

推荐阅读更多精彩内容