[LintCode] Topological Sorting

 Given an directed graph, a topological order of the graph nodes is defined as follow:

  • For each directed edge A -> B in graph, A must appear before B in the order list.
  • The first node in the order can be any node in the graph with no nodes direct to it.

Find any topological order for the given graph.

Example

For graph as follow:

picture

The topological order can be:

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

Can you do it in both BFS and DFS?

 

Solution 1. DFS, O(n + m) runtime, O(n) space

Algorithm:

1. for each node that has not been explored, dfs on it. The recursive dfs call stops at sinking vertices that have no outgoing edges. At the beginning of each recursive dfs call, mark the current node as explored; Before exiting each recursive dfs call, push the current graph node to a global stack.

2. After all nodes have been explored, pop the stack and add them to the result list.

Proof of correctness: Sinking vertices in the current subgraph are always pushed to the stack first. 

 

 1 /**
 2  * Definition for Directed graph.
 3  * class DirectedGraphNode {
 4  *     int label;
 5  *     ArrayList<DirectedGraphNode> neighbors;
 6  *     DirectedGraphNode(int x) { label = x; neighbors = new ArrayList<DirectedGraphNode>(); }
 7  * };
 8  */
 9 
10 public class Solution {
11     public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
12         ArrayList<DirectedGraphNode> result = new ArrayList<DirectedGraphNode>();
13         if(graph == null || graph.size() == 0)
14         {
15             return result;
16         }
17         Stack<DirectedGraphNode> stack = new Stack<DirectedGraphNode>();
18         HashSet<DirectedGraphNode> visited = new HashSet<DirectedGraphNode>();
19         for(DirectedGraphNode node : graph)
20         {
21             if(!visited.contains(node))
22             {
23                 topSortHelper(node, visited, stack);
24             }
25         }
26         while(!stack.empty())
27         {
28             result.add(stack.pop());
29         }
30         return result;
31     }
32     private void topSortHelper(DirectedGraphNode node,
33                             HashSet<DirectedGraphNode> visited,
34                             Stack<DirectedGraphNode> stack)
35     {
36         visited.add(node);
37         for(DirectedGraphNode neighbor : node.neighbors)
38         {
39             if(!visited.contains(neighbor))
40             {
41                 topSortHelper(neighbor, visited, stack);
42             }
43         }
44         stack.push(node);
45     }
46 }

 

Solution 2. BFS, O(n + m) runtime, O(n) space 

Algorithm:

1. construct a map that stores the number of incoming edges of each graph node. O(m) runtime

2. add graph nodes that have no incoming edges to the queue and result list. O(n) runtime

3. dequeue nodes from the queue one at a time, and update its neighbors's incoming edges by deducting 1.

4. if a neighbor node's incoming edges number becomes 0, add this neighbor node to the queue and the result list.

5. repeat the steps 3 and 4 until the queue is empty. 

 1 public class Solution {
 2     public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
 3         ArrayList<DirectedGraphNode> result = new ArrayList<DirectedGraphNode>();
 4         //this hash map stores how many incoming edges each node has.
 5         //if a node has 0 incoming edges, then it does not get stored in this hash map
 6         HashMap<DirectedGraphNode, Integer> map = new HashMap<DirectedGraphNode, Integer>();
 7         for(DirectedGraphNode node : graph)
 8         {
 9             for(DirectedGraphNode neighbor : node.neighbors)
10             {
11                 if(map.containsKey(neighbor))
12                 {
13                     map.put(neighbor, map.get(neighbor) + 1);
14                 }
15                 else
16                 {
17                     map.put(neighbor, 1);
18                 }
19             }
20         }
21         
22         Queue<DirectedGraphNode> queue = new LinkedList<DirectedGraphNode>();
23         //First add all the nodes that only have outgoing edges 
24         //the order among these nodes do not matter
25         for(DirectedGraphNode node : graph)
26         {
27             if(!map.containsKey(node))
28             {
29                 queue.offer(node);
30                 result.add(node);
31             }
32         }
33         while(!queue.isEmpty())
34         {
35             //node has been added to the result list, so we need to deduct 1
36             //for node's all neighbors.
37             DirectedGraphNode node = queue.poll();
38             for(DirectedGraphNode neighbor : node.neighbors)
39             {
40                 map.put(neighbor, map.get(neighbor) - 1);
41                 //neighbor has no incoming edges in the remaining subgraph
42                 if(map.get(neighbor) == 0)
43                 {
44                     result.add(neighbor);
45                     queue.offer(neighbor);
46                 }
47             }
48         }
49         return result;
50     }
51 }

 

Related Problems

Parallel Courses

Course Schedule 

Course Schedule II

Sequence Reconstruction

 

posted @ 2017-11-07 12:44  Review->Improve  阅读(404)  评论(0编辑  收藏  举报