leetcode刷题笔记: 图论 · 从入门到精通---刷通图论(1) 标准遍历

在这里插入图片描述

第一题: 547. 省份数量

在这里插入图片描述
加一个标志位即可简单的解决该问题
在这里插入图片描述
题目过于模板以至于无法评价。 但还是足足写了10min。

第二题: 802. 找到最终的安全状态

在这里插入图片描述

第三题: 841. 钥匙和房间

在这里插入图片描述

简单的遍历:dfs, bfs都可以:

class Solution {
    public boolean canVisitAllRooms(List<List<Integer>> rooms) {
        int n = rooms.size();
        boolean[] dp = new boolean[n];
        int res = 0;
        Arrays.fill(dp, false);
        Queue<Integer> queue = new LinkedList<>();
        queue.add(0);
        while (!queue.isEmpty() ) {
            int now = queue.poll();
            if ( !dp[now] ) {
                dp[now] = true;
                res++;
                for (int xx:rooms.get(now) ) {
                    queue.add(xx);
                }
            }
            else continue;
        }
        return res == n;
    }
}

第四题:1129. 颜色交替的最短路径

在这里插入图片描述
感觉要先转化成邻接表,然后像dp一样用一个二维数组去存储到每个点的可能路径步数。
图的算法还是好难啊!

抄了几家代码学了一下。

动手尝试: 得到代码如下:


class Solution {
    public int[] shortestAlternatingPaths(int n, int[][] redEdges, int[][] blueEdges) {
        int[][] res = new int[n][2];
        for (int i = 0; i < n; i++) {
            Arrays.fill(res[i], 2000);
        }
        res[0][0] = 0; res[0][1] = 0;
        // 0 上一步是 红; 1 上一步是蓝
        boolean flag = true;
        while ( flag ) {
            flag = false;
            for (int[] red:   redEdges) {
                if ( res[red[0]][1] > 101) continue;
                // 就是该位置已经可达。 
                if (res[red[0]][1] +1 < res[red[1]][0]) {
                    res[red[1]][0] = res[red[0]][1] +1;
                    flag = true;
                }
            }
            for (int[] blue: blueEdges) {
                if ( res[blue[0]][0] > 101 ) continue;
                if (res[blue[0]][0] +1  < res[blue[1]][1]) {
                    res[blue[1]][1] = res[blue[0]][0] +1;
                    flag = true;
                }
            }
        }
        int[] real_res = new int[n];
        for (int i = 0; i < n; i ++) {
            real_res[i] = Math.min(res[i][0], res[i][1]);
            if (real_res[i] > 101) {
                real_res[i] = -1;
            }
        }
        return real_res;        
    }
}

第五题: 1376. 通知所有员工所需的时间

在这里插入图片描述
很容易想到自底向上, 使用dfs可以秒出。

class Solution {
    // Integer.MAX_VALUE
    int[] time;
    int[] ma;
    int[] in;
    public int numOfMinutes(int n, int headID, int[] manager, int[] informTime) {
        ma = manager; in = informTime;
        time = new int[n];
        Arrays.fill(time, Integer.MAX_VALUE);
        for (int i = 0; i < n; i ++) {
            time[i] = dfs(i);
        }
        int res = 0;
        for (int i = 0; i < n; i++) {
            res = Math.max(res, time[i]);
        }
        return res;
    }
    int dfs (int id) {
        if (ma[id] == -1) return in[id];
        if (time[id] != Integer.MAX_VALUE) {
            return time[id];
        }
        time[id] = dfs(ma[id]) + in[id];
        return time[id];
    }
}

每次写递归都有一种戛然而止的感觉。
啥时候java加一个记忆化搜索的缓存啊? 每次这种情况都要自己实现一次。

第六题: 1466. 重新规划路线

在这里插入图片描述

class Solution {
    public int minReorder(int n, int[][] connections) {
        int res = 0;
        boolean[] dp = new boolean[n];
        boolean[] road_process = new boolean[n-1];
        Arrays.fill (dp, false);
        Arrays.fill (road_process, false);
        boolean flag = true;
        dp[0] = true;
        while ( flag ) {
            flag = false;
            for (int i = 0; i < n-1; i++) {
                if (road_process[i]) continue;
                flag = true;
                
                int source = connections[i][0], dst = connections[i][1];
                if ( dp[dst] ) {
                    road_process[i] = true;
                    dp[source] = true;
                }
                else if ( dp[source] ) {
                    road_process[i] = true;
                    res++;
                    dp[dst] = true;

                }
            }
        }
        return res;
    }
}

可能是最慢的方法。
在这里插入图片描述
使用bfs可能更快点。

我决定先转化成邻接矩阵形式, 得到代码如下:

class Solution {
    public int minReorder(int n, int[][] connections) {
        int[][] matrix = new int[n][n];
        for (int[] con:connections) {
            matrix[con[0]][con[1]] = 1;
            matrix[con[1]][con[0]] = -1;
        }
        Queue<Integer> queue = new LinkedList<>();
        int res = 0;
        queue.add(0);
        while (!queue.isEmpty()) {
            int now = queue.poll();
            for (int i = 0; i < n; i++) {
                if (matrix[i][now] == 1) {
                    queue.add(i);
                    matrix[now][i] = 0;
                } else if (matrix[i][now] == -1) {
                    queue.add(i);
                    res ++;
                    matrix[i][now] = 1;
                    matrix[now][i] = 0;
                }
            }
        }
        return res;
    }
}

果不其然,超时了,图是个稀疏图,因此应该用list存储更河里一点。
想了一下怎么存: 感觉要写出来 List<int[]>[] 这种数据结构出来了.。参考一下大佬的写法:

class Solution {
    public int minReorder(int n, int[][] connections) {
        List<Integer>[] adjacentArr = new List[n];
        for (int i = 0; i < n; i++) {
            adjacentArr[i] = new ArrayList<Integer>();
        }
        for (int[] connection : connections) {
            adjacentArr[connection[0]].add(connection[1]);
            adjacentArr[connection[1]].add(connection[0]);
        }
        int[] levels = new int[n];
        Arrays.fill(levels, -1);
        levels[0] = 0;
        Queue<Integer> queue = new ArrayDeque<Integer>();
        queue.offer(0);
        while (!queue.isEmpty()) {
            int city = queue.poll();
            List<Integer> adjacent = adjacentArr[city];
            for (int next : adjacent) {
                if (levels[next] < 0) {
                    levels[next] = levels[city] + 1;
                    queue.offer(next);
                }
            }
        }
        int reorder = 0;
        for (int[] connection : connections) {
            if (levels[connection[0]] < levels[connection[1]]) {
                reorder++;
            }
        }
        return reorder;
    }
}

原来可以在遍历的时候先不着急更改录得方向,不然也不好判断, 先当作双向图遍历并记录每个节点的层级,以为这个实际上是要变成一个树的, 所以最终层次就应该跟书的方向一致。

第七题: 797. 所有可能的路径

在这里插入图片描述

简单的回溯, 简单题学语法:

class Solution {
    List<List<Integer>> ans = new ArrayList<List<Integer>>();
    Deque<Integer> stack = new ArrayDeque<Integer>();

    public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
        stack.offerLast(0);
        dfs(graph, 0, graph.length - 1);
        return ans;
    }

    public void dfs(int[][] graph, int x, int n) {
        if (x == n) {
            ans.add(new ArrayList<Integer>(stack));
            return;
        }
        for (int y : graph[x]) {
            stack.offerLast(y);
            dfs(graph, y, n);
            stack.pollLast();
        }
    }
}

都要忘记list 的操作了:

 ans.add(new ArrayList<Integer>(stack));
stack.offerLast(y);
stack.pollLast();

第八题: 1192. 查找集群内的关键连接

在这里插入图片描述
一眼不会,但感觉是去找到所有的环,不组成环的连接就不是。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ko no 辉夜 da

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值