[Cracking the Coding Interview] 4.1 Route Between Nodes 节点间的路径

Given a directed graph, design an algorithm to find out whether there is a route between nodes.

 

这道题让我们判断给定的一个图的任意两个节点间是否有路径。首先我们要知道如何定义一个图, 一般最常用的两种表示图的方法是: Adjacency Matrix 和 Adjacency List

对选择用哪种方法来表示图取决于你要做什么样的操作和使用的难易程度。下面稍微总结了一下这两种方法的优缺点:

Adjacency Matrix

优点:邻接矩阵容易表示并且是用的过程可以清楚的看到节点之间的关系。删除一条边需要O(1)时间复杂度,判断两个节点间是否有路径非常快,只需要O(1)时间复杂度。

缺点:空间复杂度比较大O(V^2). 即使是稀疏矩阵也需要同样的空间。如果增加一个节点需要O(V^2)的时间复杂度。

Adjacency List

 1 class Node
 2   attr_accessor :name, :neighbors
 3   
 4   def initialize(name)
 5     @name = name
 6     @neighbors = []
 7   end
 8 end
 9 
10 class Graph
11   attr_accessor :nodes
12   
13   def initialize
14     @nodes = []
15   end
16 end

优点:节省空间O(V+E). 增加一个节点很容易O(1)。

缺点:判断两个节点是否右边不是很快,需要O(V)的时间复杂度。

 

所以这道题在使用不同的图的表示方法的时候,判断两点间的路径方法是不一样的。我们假设使用Adjacency List的方法来表示图。

如何判断节点间是否有路径呢?这道题很简单,我们只需要使用DFS或者BFS来遍历整个图就可以了。

参见如下代码:

BFS Version

class Node
  attr_accessor :name, :neighbors, :visited

  def initialize(name)
    @name = name
    @neighbors = []
    @visited = false
  end
end

def has_route?(node1, node2)
  return false if node1.nil? || node2.nil?
  
  q = Queue.new
  node1.visited = true
  q << node1
  
  while !q.empty?
    cur = q.pop
    
    return true if cur.name == node2.name
    
    cur.neighbors.each do |n|
      if !n.visited
        n.visited = true
        q << n
      end
    end
  end
  false
end

 

DFS Version

class Node
  attr_accessor :name, :neighbors, :visited

  def initialize(name)
    @name = name
    @neighbors = []
    @visited = false
  end
end

def has_route?(node1, node2)
  return false if node1.nil? || node2.nil?
  return true if node1.name == node2.name
  
  node1.visited = true
  node1.neighbors.each do |n|
    next if n.visited
    if has_route?(n, node2)
      return true
    end
  end
  false
end

 

posted @ 2018-06-15 04:36 infinitycoder 阅读(...) 评论(...) 编辑 收藏