圖演算法-LeetCode 133、207(拓撲排序,鄰接表建立)

  • 2019 年 10 月 11 日
  • 筆記

點擊上方「演算法工程師之路」,選擇「星標」公眾號

重磅乾貨,第一時間送達

作者:TeddyZhang,公眾號:演算法工程師之路

貪心演算法問題:LeetCode #133 #207

編程題

【LeetCode #133】克隆圖

給定無向連通圖中一個節點的引用,返回該圖的深拷貝(克隆)。圖中的每個節點都包含它的值 val(Int) 和其鄰居的列表(list[Node])。

解釋: 節點 1 的值是 1,它有兩個鄰居:節點 2 和 4 。 節點 2 的值是 2,它有兩個鄰居:節點 1 和 3 。 節點 3 的值是 3,它有兩個鄰居:節點 2 和 4 。 節點 4 的值是 4,它有兩個鄰居:節點 1 和 3 。

提示:

  • 節點數介於 1 到 100 之間。
  • 無向圖是一個簡單圖,這意味著圖中沒有重複的邊,也沒有自環。
  • 由於圖是無向的,如果節點 p 是節點 q 的鄰居,那麼節點 q 也必須是節點 p 的鄰居。
  • 必須將給定節點的拷貝作為對克隆圖的引用返回。

解題思路:

克隆圖,並且是無向連通圖,因此可以使用map來保存兩個節點之間的連接關係,如果在map中沒有該節點tmp,則新建節點tmp_copy將該節點存入map中,然後遍歷該節點的所有鄰居,並遞拷貝其所有鄰居節點至tmp_copy的鄰居數組中。

C++程式碼:

/*  // Definition for a Node.  class Node {  public:      int val;      vector<Node*> neighbors;        Node() {}        Node(int _val, vector<Node*> _neighbors) {          val = _val;          neighbors = _neighbors;      }  };  */  class Solution {  public:      map<Node*,Node*> mp;      Node* cloneGraph(Node* node) {          if(!node)   return nullptr;          if(mp.count(node))  return mp[node];  // 如果存在,就不用新建了          Node* tmp = new Node(node -> val);          mp[node] = tmp;          for(int i = ; i < node -> neighbors.size(); ++ i){              if(node -> neighbors[i])    tmp -> neighbors.push_back(cloneGraph(node -> neighbors[i]));          }          return tmp;      }  };  

來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/clone-graph

【LeetCode #207】課程表

現在你總共有 n 門課需要選,記為 0 到 n-1。

在選修某些課程之前需要一些先修課程。例如,想要學習課程 0 ,你需要先完成課程 1 ,我們用一個匹配來表示他們: [0,1]

給定課程總量以及它們的先決條件,判斷是否可能完成所有課程的學習?

示例 1: 輸入: 2, [[1,0]] 輸出: true 解釋: 總共有 2 門課程。學習課程 1 之前,你需要完成課程 0。所以這是可能的。 示例 2: 輸入: 2, [[1,0],[0,1]] 輸出: false 解釋: 總共有 2 門課程。學習課程 1 之前,你需要先完成課程 0;並且學習課程 0 之前,你還> 應先完成課程 1。這是不可能的。

說明:

輸入的先決條件是由邊緣列表表示的圖形,而不是鄰接矩陣。詳情請參見圖的表示法。 你可以假定輸入的先決條件中沒有重複的邊。

解題思路:

由於本題目中的每個課程之間都有相應的聯繫,因此我們可以根據課程關係來構建一個有向圖,如果在這個有向圖中存在一個循環,那麼則不能學完所有的課程,因為每個課程都需要每個先決條件的課程。一個很簡單的思路是使用拓撲排序演算法,可以判斷一個循環是否存在於一個有向圖中。

拓撲排序演算法:計算圖中所有節點的入度,如果某些節點的入度為零,則壓入到隊列todo中,接著循環彈出隊列中的節點(即入讀為零的節點),同時將下一個節點中入度為零的節點壓入隊列中,如果最後圖都可以分離開,也就在此過程中,每個節點在分離時都可能入度為零。說明這個有向圖中沒有循環,否則則有循環。

C++程式碼(拓撲排序):

bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {          std::unordered_map<int, int> indegree;          for(auto& v : prerequisites) {              indegree[v[]]++;          }          queue<int> que;          for(int i=; i<numCourses; ++i) {             if(indegree[i] == ) {                 que.push(i);             }          }          int cnt = ;          while(!que.empty()) {              int k = que.front();              que.pop();              cnt++;              for(auto& v : prerequisites) {                  if(k == v[]) {                      if(--indegree[v[]] == ) {                          que.push(v[]);                      }                  }              }          }          if(cnt != numCourses)              return false;          return true;  

來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/course-schedule

文章來源:公眾號 (演算法工程師之路)