-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from modern-dev/union-find
feat: adds Disjoint Set implementation #patch
- Loading branch information
Showing
2 changed files
with
141 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// Copyright 2020. The GTL Authors. All rights reserved. | ||
// https://github.com/modern-dev/gtl | ||
// Use of this source code is governed by the MIT | ||
// license that can be found in the LICENSE file. | ||
|
||
package gtl | ||
|
||
type DisjointSet struct { | ||
size int | ||
rank, parent []int | ||
} | ||
|
||
// NewDisjointSet returns an object representing a set containing n element. | ||
func NewDisjointSet(n int) *DisjointSet { | ||
inst := &DisjointSet{ | ||
n, | ||
make([]int, n), | ||
make([]int, n), | ||
} | ||
|
||
for i := 0; i < n; i++ { | ||
inst.parent[i] = i | ||
} | ||
|
||
return inst | ||
} | ||
|
||
// Len returns the size of the disjoint set. | ||
// Complexity - O(1). | ||
func (this *DisjointSet) Len() int { | ||
return this.size | ||
} | ||
|
||
// Find returns the root of the tree that contains x. | ||
// Complexity - O(α(n)), where α is the inverse Ackermann function. | ||
func (this *DisjointSet) Find(x int) int { | ||
if this.parent[x] != x { | ||
this.parent[x] = this.Find(this.parent[x]) | ||
} | ||
|
||
return this.parent[x] | ||
} | ||
|
||
// Union merges the sets represented by x node and the y node into a single set. | ||
// Returns whether or not the nodes were disjoint before the union operation (i.e. if the operation had an effect). | ||
// Complexity - O(α(n)), where α is the inverse Ackermann function. | ||
func (this *DisjointSet) Union(x, y int) bool { | ||
xSet, ySet := this.Find(x), this.Find(y) | ||
|
||
if xSet == ySet { | ||
return false | ||
} | ||
|
||
if this.rank[xSet] < this.rank[ySet] { | ||
this.parent[xSet] = ySet | ||
} else if this.rank[xSet] > this.rank[ySet] { | ||
this.parent[ySet] = xSet | ||
} else { | ||
this.parent[ySet] = xSet | ||
this.rank[xSet] = this.rank[xSet] + 1 | ||
} | ||
|
||
return true | ||
} |
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,77 @@ | ||
// Copyright 2020. The GTL Authors. All rights reserved. | ||
// https://github.com/modern-dev/gtl | ||
// Use of this source code is governed by the MIT | ||
// license that can be found in the LICENSE file. | ||
|
||
package gtl | ||
|
||
import ( | ||
"sort" | ||
"testing" | ||
) | ||
|
||
func TestNewDisjointSet(t *testing.T) { | ||
expected := 5 | ||
ds := NewDisjointSet(expected) | ||
|
||
if ds.Len() != expected { | ||
t.Errorf("Expected to get %d, got %d", expected, ds.Len()) | ||
} | ||
} | ||
|
||
func TestUnionFind(t *testing.T) { | ||
ds := NewDisjointSet(5) | ||
ds.Union(0, 2) | ||
ds.Union(4, 2) | ||
ds.Union(3, 1) | ||
|
||
given1, given2 := ds.Find(4) == ds.Find(0), ds.Find(1) == ds.Find(0) | ||
|
||
if !given1 { | ||
t.Errorf("Expected to get %t, got %t", true, given1) | ||
} | ||
|
||
if given2 { | ||
t.Errorf("Expected to get %t, got %t", false, given2) | ||
} | ||
} | ||
|
||
func TestLeetcode1101(t *testing.T) { | ||
logs, N := [][]int{{20190101, 0, 1}, {20190104, 3, 4}, {20190107, 2, 3}, {20190211, 1, 5}, {20190224, 2, 4}, {20190301, 0, 3}, {20190312, 1, 2}, {20190322, 4, 5}}, 6 | ||
expected, given := 20190301, earliestAcq(logs, N) | ||
|
||
if given != expected { | ||
t.Errorf("Expected to get %d, got %d", given, expected) | ||
} | ||
} | ||
|
||
func earliestAcq(logs [][]int, N int) int { | ||
/* | ||
* 1101. The Earliest Moment When Everyone Become Friends | ||
* https://leetcode.com/problems/the-earliest-moment-when-everyone-become-friendsz | ||
* | ||
* In a social group, there are N people, with unique integer ids from 0 to N-1. | ||
* We have a list of logs, where each logs[i] = [timestamp, id_A, id_B] contains a non-negative integer timestamp, and the ids of two different people. | ||
* Each log represents the time in which two different people became friends. Friendship is symmetric: if A is friends with B, then B is friends with A. | ||
* Let's say that person A is acquainted with person B if A is friends with B, or A is a friend of someone acquainted with B. | ||
* Return the earliest time for which every person became acquainted with every other person. Return -1 if there is no such earliest time. | ||
*/ | ||
|
||
ds := NewDisjointSet(N) | ||
|
||
sort.Slice(logs, func(i, j int) bool { | ||
return logs[i][0] < logs[j][0] | ||
}) | ||
|
||
for i := 0; i < len(logs); i++ { | ||
if ds.Union(logs[i][1], logs[i][2]) { | ||
N-- | ||
} | ||
|
||
if N == 1 { | ||
return logs[i][0] | ||
} | ||
} | ||
|
||
return -1 | ||
} |