The Find if Path Exists in Graph problem involves determining whether there is a path between two given nodes (source and destination) in an undirected graph. The graph is represented by n nodes and a list of edges, where each edge specifies a connection between two nodes.
Given:
n: Number of nodes in the graph.
edges: List of edges where each edge is represented as [u, v], indicating an undirected edge between node u and node v.
source: The starting node for the path.
destination: The target node to reach.
Objective:
You need to implement a solution that can determine if there exists a path from the source node to the destination node in the given graph.
Output:
Return True if there exists a path from source to destination, otherwise return False.
解題:
方法一(depth first search):
-
重構給出的圖結構
題目給出的是一對對二維陣列(向量表)edges,用來表示圖中所有的邊。
重構:從已有的二維陣列中構建一個鄰接表,這會讓之後遍歷每一個節點和它的相鄰節點變得高效。 -
DFS函式的邏輯:
1.)我們需要一個集合visited來儲存每次迴圈訪問過的節點,每次只要是訪問過的節點,都把它放到visite集合中。
2.) 構建一個遞迴函式,從source節點開始,首先判斷這個source是不是就是要找的destination,如果是則返回true,否則找到和source相連線的所有鄰節點,選擇其中一個並判斷:這個節點有沒有被遍歷過(是否在visited中能找到),如果沒有,則選中它作為遞迴的起點,把它作為新的source遞迴呼叫這個函式,重複以上的操作。
3.)透過遞迴可以充分遍歷完圖中的所有節點,如果最終沒有找到預先給定的destination,則表示不存在從source到destination的路徑,返回false.
class Solution {
public:
bool validPath(int n, vector<vector<int>>& edges, int source, int destination) {
unordered_map<int, vector<int>> graph;
for (const auto &edge: edges) {
int u = edge[0];
**int v = edge[1];
graph[u].push_back(v);
graph[v].push_back(u);
}
unordered_set<int> visited;
return dfs(source, destination, graph, visited);
}
bool dfs(int node, int destination, unordered_map<int, vect**or<int>> &graph, unordered_set<int> &visited) {
if (node == destination) {**
return true;
}
visited.insert(node);
for (int neighbor: graph[node]) {
if (visited.find(neighbor) == visited.end()) {
if (dfs(neighbor, destination, graph, visited)) {
return true;
}
}
}
return false;
}
};
方法二(breadth-first search)
- 首先也是和方法一一樣重構圖結構。
- BFS函式邏輯:
1.)同樣需要建立一個集合visited用來儲存訪問過的節點,以保證遍歷的過程中迴圈的有界性以及避免重複訪問同一個節點。
2.)這次用一個while迴圈替代遞迴,對於while,需要創造一個結束的邊界條件:使用queue容器並判斷queue容器是否為空,為空則停止迴圈。具體操作:把關注的那個節點(沒有被訪問過的)放入佇列queue中,進入迴圈while判斷,把這個節點pop出去,並把這個節點儲存到visted集合內。找到和當前節點相鄰的同時未被訪問過的一個新節點,把它作為新關注的節點並放到佇列中,進入下一輪while迴圈,確定這個節點是否等於destination,如果等於則結束迴圈,否則找一個與該節點相鄰的下一個鄰接點重複迴圈,如果最後queue在進行while判斷時為空,那麼迴圈終止,表示遍歷完所有節點,沒有找到從source到destination的路徑。
class Solution {
public:
bool validPath(int n, vector<vector<int>>& edges, int source, int destination) {
unordered_map<int, vector<int>> graph;
for (const auto &edge: edges) {
int u = edge[0];
int v = edge[1];
graph[u].push_back(v);
graph[v].push_back(u);
}
queue<int> queue;
unordered_set<int> visited;
queue.push(source);
visited.insert(source);
while (!queue.empty()) {
int node = queue.front();
queue.pop();
if (node == destination) {
return true;
}
for (int neighbor: graph[node]) {
if (visited.find(neighbor) == visited.end()) {
visited.insert(neighbor);
queue.push(neighbor);
}
}
}
return false;
}
};