graph

2021-07-01

图除了本篇基础篇之外,还有BFS, DFS, Union-find, Shortest Path

Graph

// 133. Clone Graph
// BFS
/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> neighbors;
    Node() {
        val = 0;
        neighbors = vector<Node*>();
    }
    Node(int _val) {
        val = _val;
        neighbors = vector<Node*>();
    }
    Node(int _val, vector<Node*> _neighbors) {
        val = _val;
        neighbors = _neighbors;
    }
};
*/
class Solution {
 public:
  unordered_map<Node*, Node*> record_;
  
  Node* cloneGraph(Node* node) {
    if (!node) return nullptr;
    
    queue<Node*> visiting({node});
    
    while (!visiting.empty()) {
      const auto tp = visiting.front();
      visiting.pop();
      if (record_.find(tp) == record_.end()) {
        Node* tp_map = new Node(tp->val);
        record_[tp] = tp_map;
      }
      for (const auto& node : tp->neighbors) {
        if (record_.find(node) == record_.end()) {
          visiting.push(node);
          record_[node] = new Node(node->val);
        } 
        record_[tp]->neighbors.push_back(record_[node]);
      }
    }
    return record_[node];
  }
};
// DFS
class Solution {
 public:
  unordered_map<Node*, Node*> record_;
  
  Node* cloneGraph(Node* node) {
    if (!node) return nullptr;
    
    if (record_.find(node) != record_.end())
      return record_[node];
    
    Node* new_node = new Node(node->val);
    record_[node] = new_node;
    
    for (const auto child_node : node->neighbors) {
      Node* new_child_node = cloneGraph(child_node);
      record_[child_node] = new_child_node;
      new_node->neighbors.push_back(new_child_node);
    }
    
    return record_[node];
  }
};

// 743. Network Delay Time
// Djikstra shortest path
// Old method
class Solution {
 public:
  struct Node {
    int index = -1;  
    int distance = INT_MAX;
    int precurssor = -1;
    Node(const int idx, const int dis) {
      index = idx;
      distance = dis;   
    }   
  };
    
  struct Comp {
    bool operator()(const struct Node& node1, const struct Node& node2) {
      return node1.distance >= node2.distance;  
    }  
  };
    
  using InitQueue = priority_queue<Node, vector<Node>, Comp>;
  InitQueue InitPriorityQueue(const int N, const int K) {
    InitQueue queue;  
    for (int i = 0; i < N; ++i) {
      if (i != K) queue.push(Node(i, INT_MAX));
    }
    Node start(K, 0);
    queue.push(start);
      
    return queue;
  }
    
  int networkDelayTime(vector<vector<int>>& times, int N, int K) {
    InitQueue Q = InitPriorityQueue(N, K);
    unordered_map<int, Node> record;
    record.emplace(K, Node(K, 0)); 
    unordered_map<int, vector<vector<int>>> edges;
    for (const auto time : times) edges[time[0]].push_back(time);
    int longest_dis = -1;
    unordered_set<int> visited; 
    while (!Q.empty()) {
      const auto tp = Q.top();
      if (tp.distance == INT_MAX) { 
        if (record.size() < N)
          return -1; 
        else break;
      }  
      Q.pop();
      if (visited.find(tp.index) != visited.end()) continue; 
      for (const auto edge : edges[tp.index]) {
        const int new_dis = edge[2] + tp.distance;
        if ((record.find(edge[1]) == record.end()) || record.at(edge[1]).distance > new_dis) 
        {
          Node new_node(edge[1], new_dis);
          new_node.precurssor = edge[0];  
          Q.push(new_node);
          record.emplace(edge[1], new_node).first->second = new_node;  
        }  
      }
      visited.insert(tp.index);  
    }
    for (const auto m : record) {
      longest_dis = max(m.second.distance, longest_dis);
    }
    return longest_dis;
  }
};

// 785. Is Graph Bipartite?
// Method 1 UF
class Solution {
 private:
  class UnionFind {
   public:
    UnionFind(const int N) {
      record_.resize(N);
      rank_.resize(N);
      for (int i = 0; i < N; ++i)
        record_[i] = i;
    }
    
    int Find(const int num) {
      if (num != record_[num])
        record_[num] = Find(record_[num]);
      return record_[num];
    }
    
    void Union(const int num1, const int num2) {
      const int p1 = Find(num1);
      const int p2 = Find(num2);
      if (p1 != p2) {
        if (rank_[p1] > rank_[p2]) {
          record_[p2] = p1;
        } else {
          record_[p1] = p2;
          if (rank_[p1] == rank_[p2])
            ++rank_[p2];
        }
      }
    }
    
    vector<int> record_;
    vector<int> rank_;
  };
 public:
  bool isBipartite(vector<vector<int>>& graph) {
    if (graph.size() < 2) return true;
    UnionFind uf(graph.size());
    for (int i = 0; i < graph.size(); ++i) {
      if (!graph[i].size()) continue;
      for (int j = 0; j < graph[i].size(); ++j) {
        for (int k = j + 1; k < graph[i].size(); ++k) {
          uf.Union(graph[i][j], graph[i][k]);
        }       
      }
    }
    for (int i = 0; i < graph.size(); ++i) {
      if (!graph[i].size()) continue;
      for (const auto& v : graph[i]) {
        if (uf.Find(i) == uf.Find(v))
          return false;
      }
    }
    return true;
  }
};
// BFS
bool isBipartite(vector<vector<int>>& graph) {
  unordered_set<int> r1;
  unordered_set<int> r2;
  for (int i = 0; i < graph.size(); ++i) {
    if (!graph[i].size() || r1.count(i) || r2.count(i))
      continue;
    queue<int> visiting({i});
    r1.insert(i);
    bool take_1 = true;
    while (!visiting.empty()) {
      const int size = visiting.size();
      auto& tmp1 = take_1?r1:r2;
      auto& tmp2 = take_1?r2:r1;
      for (int j = 0; j < size; ++j) {
        const int tp = visiting.front();
        visiting.pop();
        for (const auto& v : graph[tp]) {
          if (tmp1.count(v) > 0) return false;
          const auto [it, s] = tmp2.insert(v);
          if (s) visiting.push(v);
        }
      }
      take_1 ^= true;
    }
  }
  return true;
}
// DFS
class Solution {
 public:
  bool DetectCycle(const int num, const vector<vector<int>>& graph,
                   unordered_set<int>& r1, unordered_set<int>& r2) {
    if (r1.count(num)) {
      return false;
    }
    r1.insert(num);
    for (const auto& v:graph[num]) {
      if (r1.count(v)) return true;
      if (DetectCycle(v, graph, r2, r1))
        return true;
    }
    return false;
  }
  
  bool isBipartite(vector<vector<int>>& graph) {
    unordered_set<int> r1;
    unordered_set<int> r2;
    for (int i = 0; i < graph.size(); ++i) {
      if (!graph[i].size() || r1.count(i) || r2.count(i))
        continue;
      if (DetectCycle(i, graph, r1, r2))
        return false;
    }
    return true;
  }
};

// 399. Evaluate Division
// Method 1: DFS
double CalculateEquation(const string& s1, const string& s2, const double cur,
                         unordered_map<string, unordered_map<string, double>>& edges,
                         unordered_set<string>& visited) {
  if (s1 == s2) {
    return edges.count(s1) > 0 ? cur:-1.0;
  }
  if (visited.count(s1) > 0) return -1.0;
  visited.insert(s1);  
  double num = 1.0;
  if (edges.count(s1) > 0 && edges[s1].size() > 0) {
    for (const auto& v : edges[s1]) {
      num = CalculateEquation(v.first, s2, cur * v.second, edges, visited);
      if (num > 0) return num;
    }
  }
  return -1.0;
}

vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, 
                            vector<vector<string>>& queries) {
  unordered_map<string, unordered_map<string, double>> edges;
  for (int i = 0; i < values.size(); ++i) {
    edges[equations[i][0]].emplace(equations[i][1], values[i]);
    edges[equations[i][1]].emplace(equations[i][0], 1.0/values[i]);
  }
  vector<double> ans;
  for (const auto& query : queries) {
    unordered_set<string> visited;
    ans.push_back(CalculateEquation(query[0], query[1], 1.0, edges, visited)); 
  }
  return ans;
}
// Method 2: BFS
vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, 
                            vector<vector<string>>& queries) {
  unordered_map<string, unordered_map<string, double>> edges;
  for (int i = 0; i < values.size(); ++i) {
    edges[equations[i][0]].emplace(equations[i][1], values[i]);
    edges[equations[i][1]].emplace(equations[i][0], 1.0/values[i]);
  }
  vector<double> ans;
  for (const auto& query : queries) {
    unordered_set<string> visited;
    queue<pair<string, double>> que;
    que.emplace(make_pair(query[0], 1.0));
    double num = -1.0;
    while (!que.empty()) {
      const auto tp = que.front();
      que.pop();
      if (visited.count(tp.first) > 0)
        continue;
      if (!edges.count(tp.first)) {
        visited.insert(tp.first);
        continue;
      }
      for (const auto& edge : edges[tp.first]) {
        if (edge.first == query[1]) {
          num = edge.second * tp.second;
          break;
        } else {
          que.emplace(make_pair(edge.first, edge.second * tp.second));
        }
      }
      if (num > 0) break;
      visited.insert(tp.first);
    }
    ans.push_back(num);
  }
  return ans;
}

// 332. Reconstruct Itinerary
class Solution {
 public:
  bool find_ = false;
  vector<string> ans_;
  
  void FindItinerary(const unordered_map<string, set<string>>& edges,
                     const string& stt, unordered_map<string, int>& count,
                     vector<string> ans) {
    ans.push_back(stt);
    if (!count.size()) {
      find_ = true;
      ans_ = ans;
    }
    if (find_) return;
    if (!edges.count(stt)) return;
    for (const auto& t : edges.at(stt)) {
      const auto& str = stt + t;
      if (!count.count(str)) continue;
      --count[str];
      if (count[str] <= 0) count.erase(str);
      FindItinerary(edges, t, count, ans);
      ++count[str];
    }
  }
  
  vector<string> findItinerary(vector<vector<string>>& tickets) {
    unordered_map<string, set<string>> edges;
    unordered_map<string, int> count;
    for (const auto& edge : tickets) {
      edges[edge[0]].emplace(edge[1]);
      ++count[edge[0]+edge[1]];
    }
    vector<string> ans;
    FindItinerary(edges, "JFK", count, ans);
    return ans_;
  }
};

// Good problem: 631. Design Excel Sum Formula
To 854.