-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add solutions, explanation and update the README file of the day of 684
- Loading branch information
Aarzoo
committed
Jan 28, 2025
1 parent
0e7f8de
commit 5f6d8d0
Showing
8 changed files
with
227 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
Algorithms/src/684. Redundant Connection/Code/solution.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
class Solution | ||
{ | ||
public: | ||
vector<int> findRedundantConnection(vector<vector<int>> &edges) | ||
{ | ||
int n = edges.size(); | ||
vector<int> parent(n + 1), rank(n + 1, 0); | ||
|
||
// Initialize each node as its own parent | ||
for (int i = 0; i <= n; i++) | ||
{ | ||
parent[i] = i; | ||
} | ||
|
||
// Find function with path compression | ||
function<int(int)> find = [&](int node) | ||
{ | ||
if (parent[node] != node) | ||
parent[node] = find(parent[node]); // Path compression | ||
return parent[node]; | ||
}; | ||
|
||
// Union function by rank | ||
auto unionSets = [&](int u, int v) | ||
{ | ||
int rootU = find(u), rootV = find(v); | ||
if (rootU == rootV) | ||
return false; // Cycle detected | ||
if (rank[rootU] > rank[rootV]) | ||
parent[rootV] = rootU; | ||
else if (rank[rootU] < rank[rootV]) | ||
parent[rootU] = rootV; | ||
else | ||
{ | ||
parent[rootV] = rootU; | ||
rank[rootU]++; | ||
} | ||
return true; | ||
}; | ||
|
||
// Process each edge | ||
for (auto &edge : edges) | ||
{ | ||
if (!unionSets(edge[0], edge[1])) | ||
return edge; | ||
} | ||
return {}; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
func findRedundantConnection(edges [][]int) []int { | ||
parent := make([]int, len(edges)+1) | ||
rank := make([]int, len(edges)+1) | ||
|
||
for i := range parent { | ||
parent[i] = i | ||
} | ||
|
||
var find func(int) int | ||
find = func(node int) int { | ||
if parent[node] != node { | ||
parent[node] = find(parent[node]) | ||
} | ||
return parent[node] | ||
} | ||
|
||
union := func(u, v int) bool { | ||
rootU, rootV := find(u), find(v) | ||
if rootU == rootV { | ||
return false | ||
} | ||
if rank[rootU] > rank[rootV] { | ||
parent[rootV] = rootU | ||
} else if rank[rootU] < rank[rootV] { | ||
parent[rootU] = rootV | ||
} else { | ||
parent[rootV] = rootU | ||
rank[rootU]++ | ||
} | ||
return true | ||
} | ||
|
||
for _, edge := range edges { | ||
if !union(edge[0], edge[1]) { | ||
return edge | ||
} | ||
} | ||
return nil | ||
} |
41 changes: 41 additions & 0 deletions
41
Algorithms/src/684. Redundant Connection/Code/solution.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
class Solution { | ||
public int[] findRedundantConnection(int[][] edges) { | ||
int n = edges.length; | ||
int[] parent = new int[n + 1]; | ||
int[] rank = new int[n + 1]; | ||
|
||
for (int i = 0; i <= n; i++) { | ||
parent[i] = i; | ||
rank[i] = 0; | ||
} | ||
|
||
// Find function with path compression | ||
int find(int node) { | ||
if (parent[node] != node) | ||
parent[node] = find(parent[node]); | ||
return parent[node]; | ||
} | ||
|
||
// Union function by rank | ||
boolean unionSets(int u, int v) { | ||
int rootU = find(u); | ||
int rootV = find(v); | ||
if (rootU == rootV) return false; | ||
if (rank[rootU] > rank[rootV]) | ||
parent[rootV] = rootU; | ||
else if (rank[rootU] < rank[rootV]) | ||
parent[rootU] = rootV; | ||
else { | ||
parent[rootV] = rootU; | ||
rank[rootU]++; | ||
} | ||
return true; | ||
} | ||
|
||
// Process each edge | ||
for (int[] edge : edges) { | ||
if (!unionSets(edge[0], edge[1])) return edge; | ||
} | ||
return new int[0]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
var findRedundantConnection = function (edges) { | ||
let parent = Array(edges.length + 1) | ||
.fill(0) | ||
.map((_, i) => i); | ||
let rank = Array(edges.length + 1).fill(0); | ||
|
||
function find(node) { | ||
if (parent[node] !== node) parent[node] = find(parent[node]); // Path compression | ||
return parent[node]; | ||
} | ||
|
||
function union(u, v) { | ||
let rootU = find(u), | ||
rootV = find(v); | ||
if (rootU === rootV) return false; | ||
if (rank[rootU] > rank[rootV]) parent[rootV] = rootU; | ||
else if (rank[rootU] < rank[rootV]) parent[rootU] = rootV; | ||
else { | ||
parent[rootV] = rootU; | ||
rank[rootU]++; | ||
} | ||
return true; | ||
} | ||
|
||
for (let [u, v] of edges) { | ||
if (!union(u, v)) return [u, v]; | ||
} | ||
return []; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from typing import List | ||
|
||
class Solution: | ||
def findRedundantConnection(self, edges: List[List[int]]) -> List[int]: | ||
parent = list(range(len(edges) + 1)) | ||
rank = [0] * (len(edges) + 1) | ||
|
||
def find(node): | ||
if parent[node] != node: | ||
parent[node] = find(parent[node]) # Path compression | ||
return parent[node] | ||
|
||
def union(u, v): | ||
rootU, rootV = find(u), find(v) | ||
if rootU == rootV: | ||
return False # Cycle detected | ||
if rank[rootU] > rank[rootV]: | ||
parent[rootV] = rootU | ||
elif rank[rootU] < rank[rootV]: | ||
parent[rootU] = rootV | ||
else: | ||
parent[rootV] = rootU | ||
rank[rootU] += 1 | ||
return True | ||
|
||
for u, v in edges: | ||
if not union(u, v): | ||
return [u, v] | ||
return [] |
38 changes: 38 additions & 0 deletions
38
Algorithms/src/684. Redundant Connection/Explanation/explanation.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# **Intuition** | ||
|
||
When I first saw this problem, it reminded me of a cycle detection problem in an undirected graph. The problem states that we have a connected graph with **n nodes** and **n edges** (i.e., a tree with an extra edge). | ||
|
||
A **tree** with `n` nodes should have exactly `n-1` edges. Since we have `n` edges, this means there's **one extra edge** forming a cycle, and we need to **find and remove that extra edge** while keeping the graph connected. | ||
|
||
A common way to handle **cycle detection in an undirected graph** is by using **Union-Find (Disjoint Set Union, DSU)**. So, my first instinct was to solve this using **DSU with path compression and union by rank**. | ||
|
||
--- | ||
|
||
# **Approach** | ||
|
||
To find the **redundant edge** efficiently, we use the **Union-Find (DSU) data structure**: | ||
|
||
1. **Initialize DSU:** | ||
- We maintain a parent array where each node is its own parent initially. | ||
- We also maintain a rank array for optimization. | ||
|
||
2. **Process each edge one by one:** | ||
- If two nodes in an edge already belong to the same connected component (i.e., they have the same root parent), then adding this edge **forms a cycle**. | ||
- This means the current edge is **redundant**, so we return it as the answer. | ||
|
||
3. **Union-Find operations:** | ||
- **Find function:** Uses path compression to keep the tree flat. | ||
- **Union function:** Uses union by rank to attach smaller trees under larger ones, keeping the structure balanced. | ||
|
||
By iterating over all edges and performing these operations, we can efficiently detect the first edge that forms a cycle. | ||
|
||
--- | ||
|
||
# **Complexity Analysis** | ||
|
||
- **Time Complexity:** \(O(n \log n)\) | ||
- The `find` and `union` operations have an **amortized** complexity of **O(α(n))**, which is nearly constant. | ||
- Since we process `n` edges, the overall complexity is **O(n α(n))**, which simplifies to **O(n log n)** in the worst case. | ||
|
||
- **Space Complexity:** **O(n)** | ||
- We maintain a `parent` and `rank` array, both of size **O(n)**. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters