leetcode:不邻接植花

题目来源:力扣

题目介绍:

有 N 个花园,按从 1 到 N 标记。在每个花园中,你打算种下四种花之一。
paths[i] = [x, y] 描述了花园 x 到花园 y 的双向路径。
另外,没有花园有 3 条以上的路径可以进入或者离开。
你需要为每个花园选择一种花,使得通过路径相连的任何两个花园中的花的种类互不相同。
以数组形式返回选择的方案作为答案 answer,其中 answer[i] 为在第 (i+1) 个花园中种植的花的种类。花的种类用 1, 2, 3, 4 表示。保证存在答案。
============================================================
示例 1:
输入:N = 3, paths = [[1,2],[2,3],[3,1]]
输出:[1,2,3]
示例 2:
输入:N = 4, paths = [[1,2],[3,4]]
输出:[1,2,1,2]
===========================================================

审题:

这道题考察的主要是图遍历知识.为每一个花园种花就是一个对图节点的遍历,不过我们需要在遍历的过程中选择符合要求类型的花.
因此,我们将这道题分为两部分:
1)构建图结构
2)图节点遍历着色(种花)

对于问题一,我们可以单独检查一个类表示图结构,也可以直接使用某种数据结构进行表示,例如Map键值对.

对于问题二,为了对图节点进行着色,我们首先考虑深度优先搜索遍历图节点,为什么深度优先呢?因为种花问题中我们的每一步选择依赖于前面的选择.如果对于当前花园,不存在合适的花型,则我们需要回溯到前一步重新着色.
在遍历每一节点过程中,我们需要为当前花园选择花类型,我们可以使用如下逻辑判断当前花类型是否符合要求:检查每一邻接花园,如果邻接花园已经选择了花型且与当前花园花色相同,则当前花色不符合要求.选择符合要求的花色进行着色,然后遍历其余节点,直至所有节点均被遍历.

看到这里,可能有人会问,会不会存在某一节点,不存在符合要求的花类型呢?按照回溯的思想,如果对于某一节点,不存在符合要求的花类型, 则我们需要回溯到上一节点,为其重新着色.然而对于该问题,事实上不存在这种可能性.因为题目中每一花园最多与三个花园邻接,而我们可以使用四种花色对花园进行着色,因此总可以对当前花园成功进行着色.不过在后文中,我们仍然提供了基于回溯的判断.使该算法实用性更广.

java算法实现:

class Solution {
    class Graph{ //无向图
        private List<Integer>[] adj;
        public Graph(int N){
            adj = (ArrayList<Integer>[])new ArrayList[N+1]; //邻接表
            for(int i = 0; i < N+1; i++)
                adj[i] = new ArrayList<Integer>();
        }
        public void addEdge(int i, int j){
            adj[i].add(j);
            adj[j].add(i);
        }
        public List<Integer> adj(int i){
            return adj[i];
        }
    }

    int[] flower;
    Graph graph;
    int[] flowertype = new int[]{1, 2, 3, 4};

    public int[] gardenNoAdj(int N, int[][] paths) {
        //构建无向图
        graph = new Graph(N);
        for(int i = 0; i < paths.length; i++)
            graph.addEdge(paths[i][0], paths[i][1]);

        flower = new int[N];
        for(int i = 0; i < N; i++)
            flower[i] = -1; //初始化为-1,表示当前花园尚未种花 
        for(int i = 0; i < N; i++)
            if(flower[i] == -1)
                dfs(i+1);   

        return flower;
    }

    private boolean ableFlower(int garden, int flowerOfGarden){
        //如果某一邻接花园的花与当前花相同,则返回false, 否则返回true
        for(int i: graph.adj(garden)){
            if(flower[i-1] != -1 && flowerOfGarden == flower[i-1])
                return false;
        }
        return true;
    }

    private boolean allGardenFlowered(){
        for(int i = 0; i < flower.length; i++)
            if(flower[i] == -1)
                return false;
        return true;
    }

    //使用深度优先搜索方法种花
    private void dfs(int garden){
        for(int f: flowertype){
            if (!allGardenFlowered() && ableFlower(garden, f)){
                //如果当前花类型允许,则搜索其尚未终止的其他邻接花园
                flower[garden-1] = f; //设置当前花园的花类型
                for(int adjGarden : graph.adj(garden)){
                    if(flower[adjGarden-1] == -1){
                        dfs(adjGarden);
                    }
                }
                break;
            }
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值