1. DFS Reachability Check for Each Edge
Intuition
For each edge (u, v), before adding it to our growing graph, check if there is already a path from u to v using DFS. If a path already exists, adding edge (u, v) would create a cycle, making (u, v) the redundant edge. Otherwise, add (u, v) to the adjacency list and continue.
Algorithm
- Initialize an empty adjacency list of size n + 1.
- For each edge
[u, v]inedges: - Run
dfs(u, v)on the current graph to check if v is reachable from u. - If reachable:
- Return
[u, v]. - Else:
- Add edge between u and v in adjacency list.
- Return empty array (fallback).
#include <iostream>#include <vector> bool dfs(int u, int target, const std::vector<std::vector<int>>& adj, std::vector<bool>& visited) { if (u == target) return true; visited[u] = true; for (int v : adj[u]) { if (!visited[v]) { if (dfs(v, target, adj, visited)) return true; } } return false;} std::vector<int> findRedundantConnectionDFS(std::vector<std::vector<int>>& edges) { int n = edges.size(); std::vector<std::vector<int>> adj(n + 1); for (const auto& e : edges) { int u = e[0], v = e[1]; std::vector<bool> visited(n + 1, false); if (dfs(u, v, adj, visited)) { return e; } adj[u].push_back(v); adj[v].push_back(u); } return {};} int main() { std::vector<std::vector<int>> edges = {{1,2},{1,3},{2,3}}; auto res = findRedundantConnectionDFS(edges); std::cout << "Redundant Edge (DFS): [" << res[0] << ", " << res[1] << "]" << std::endl; return 0;}Time & Space Complexity
- Time complexity:
O(N^2) because for each of the N edges, we may explore up to N vertices via DFS. - Space complexity:
O(N) for the adjacency list and DFS recursion stack.