LintCode第127-拓扑排序

首先我们需要明确树的层序遍历和BFS(广度优先搜索)的关系 

树的层序遍历是BFS的一种具体应用形式,即广度优先搜索在树结构上的特化

1. 层序遍历

核心思想:

应用范围:专门用于二叉树 / 普通树

遍历顺序:按层级逐层访问节点(从上到下、从左到右)

实现方式:一般使用队列

2.广度优先搜索

核心思想:

应用范围:适用于 图、树、矩阵、迷宫等各种结构

遍历顺序:从起点开始,先遍历“距离近的”,再遍历“距离远的”

“距离”在 BFS 中不是物理距离,而是“从起点出发,最少经过多少步才能到达目标”的步数.

每走一步,就是 +1 步。

BFS 就是按照“离起点多少步”的顺序,逐层推进

实现方式:一般使用队列

再来看题

描述

给定一个有向图,图节点的拓扑排序定义如下:

对于图中的每一条有向边 A -> B , 在拓扑排序中A一定在B之前.

拓扑排序中的第一个节点可以是图中的任何一个没有其他节点指向它的节点.

针对给定的有向图找到任意一种拓扑排序的顺序.

您只需要返回给定图的任何一种拓扑顺序.

样例 1:

输入:

graph = {0,1,2,3#1,4#2,4,5#3,4,5#4#5}

输出:

[0, 1, 2, 3, 4, 5]

易出错点:

拓扑排序必须统计每个节点的入度数即多少条边指向它

详细的步骤为:

1.先统计所有入度为0的节点

2.将所有入度为0的节点入队列 

3.将队列的节点依次出队 每次出队一个节点 然后记录在结果的数组中 并更新邻接节点的入度

4.如果邻接节点也变为0的话那么将该节点也加入队列

5.最终返回结果的数组 即拓扑排序的结果

注意该题目中neighbors是有方向的 所以可以提供入度信息

当前节点 ——指向→ 它的所有邻居

每个 neighbor 就是当前节点的出边目标

解决该题可以分为三大模块:

1.初始化所有节点的入度信息

即关键的这一句 统计入度信息

inDegreeMap.put(neighborNode, inDegreeMap.getOrDefault(neighborNode, 0) + 1);

2.将每个入度为0的节点统计进入队列

3.通过队列模拟宽度优先搜索

代码如下:

/**
 * Definition for Directed graph.
 * class DirectedGraphNode {
 *     int label;
 *     List<DirectedGraphNode> neighbors;
 *     DirectedGraphNode(int x) {
 *         label = x;
 *         neighbors = new ArrayList<DirectedGraphNode>();
 *     }
 * }
 */

public class Solution {
    /**
     * @param graph: A list of Directed graph node
     * @return: Any topological order for the given graph.
     */
    public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
        // 记录拓扑排序的结果
        ArrayList<DirectedGraphNode> recordQueue = new ArrayList<>();

        if (graph == null) {
            return recordQueue;
        }

        // 用于记录每个节点的入度
        Map<DirectedGraphNode, Integer> inDegreeMap = new HashMap<>();

        for (DirectedGraphNode queueNode : graph) {
            if (!inDegreeMap.containsKey(queueNode))       // 初始化

                {        
                    inDegreeMap.put(queueNode, 0);
                        }

            for (DirectedGraphNode neighborNode : queueNode.neighbors) {
                inDegreeMap.put(neighborNode, inDegreeMap.getOrDefault(neighborNode, 0) + 1);
            }
        }

        // 将所有入度为 0 的节点入队
        Queue<DirectedGraphNode> queueDirectedGraphNode = new LinkedList<>();
        for (DirectedGraphNode queueNode : graph) {
            if (inDegreeMap.get(queueNode) == 0) {
                queueDirectedGraphNode.offer(queueNode);
            }
        }

        // 拓扑排序核心逻辑(BFS)
        while (!queueDirectedGraphNode.isEmpty()) {
            DirectedGraphNode queueNode = queueDirectedGraphNode.poll();
            recordQueue.add(queueNode);

            List<DirectedGraphNode> currentNeighbors = queueNode.neighbors;
            for (DirectedGraphNode neighborNode : currentNeighbors) {
                inDegreeMap.put(neighborNode, inDegreeMap.get(neighborNode) - 1);
                if (inDegreeMap.get(neighborNode) == 0) {
                    queueDirectedGraphNode.offer(neighborNode);
                }
            }
        }

        return recordQueue;
    }
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值