algorithms

Algorithm implementations
git clone git://git.laack.co/algorithms.git
Log | Files | Refs | README

commit d10cb4dc4b88678c5b802ad76b083c08e1bcd61f
parent 69e20a4474ef66c9db5778893a9c162ef40e98c6
Author: Andrew Laack <andrew@laack.co>
Date:   Thu, 10 Sep 2026 10:38:40 -0500

Completed some union find problems

Diffstat:
Alongest-consecutive-sequence/longest-consecutive-sequence-v2.py | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Alongest-consecutive-sequence/longest-consecutive-sequence-v3.py | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alongest-consecutive-sequence/longest-consecutive-sequence.py | 24++++++++++++++++++++++++
Anumber-of-provinces/number-of-provinces-v2.cpp | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anumber-of-provinces/number-of-provinces.cpp | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Aredundant-connection/redundant-connection.cpp | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 324 insertions(+), 0 deletions(-)

diff --git a/longest-consecutive-sequence/longest-consecutive-sequence-v2.py b/longest-consecutive-sequence/longest-consecutive-sequence-v2.py @@ -0,0 +1,50 @@ +class Node(): + def __init__(self,parent,num): + self.parent = parent + self.num = num + # only accurate for root of tree + self.size = 1 + +def find(a): + if a.parent is None: + return a + return find(a.parent) + +def union(a,b): + if b is None: + return a.size + a_rep = find(a) + b_rep = find(b) + b_rep.parent = a_rep + a_rep.size += b_rep.size + return a_rep.size + +class Solution: + def search(self, current, count): + if not current in self.num_set: + return count + return self.search(current + 1, count + 1) + + def longestConsecutive(self, nums: List[int]) -> int: + # idea: + # this must be in linear time + # this means we can't sort + # we can use union find which has amortized constant time union and find ops + + # how? + # make the set of our numbers into k disjoint trees + # try to union each number with num + 1 + # return largest sized union + + nodes = {x : Node(None,x) for x in nums} + + # do unions + max_size = 0 + + for nd_num in nodes: + a = nodes.get(nd_num) + b = nodes.get(nd_num + 1) + un_size = union(a,b) + max_size = max(max_size, un_size) + + return max_size diff --git a/longest-consecutive-sequence/longest-consecutive-sequence-v3.py b/longest-consecutive-sequence/longest-consecutive-sequence-v3.py @@ -0,0 +1,58 @@ +class Node(): + def __init__(self,parent,num): + self.parent = parent + self.num = num + # only accurate for root of tree + self.size = 1 + +def find(a): + if a.parent is None: + return a + rep = find(a.parent) + a.parent = rep + return rep + +def union(a,b): + if b is None: + return a.size + a_rep = find(a) + b_rep = find(b) + + if a_rep.size > b_rep.size: + b_rep.parent = a_rep + a_rep.size += b_rep.size + return a_rep.size + else: + a_rep.parent = b_rep + b_rep.size += a_rep.size + return b_rep.size + +class Solution: + def search(self, current, count): + if not current in self.num_set: + return count + return self.search(current + 1, count + 1) + + def longestConsecutive(self, nums: List[int]) -> int: + # idea: + # this must be in linear time + # this means we can't sort + # we can use union find which has amortized constant time union and find ops + + # how? + # make the set of our numbers into k disjoint trees + # try to union each number with num + 1 + # return largest sized union + + nodes = {x : Node(None,x) for x in nums} + + # do unions + max_size = 0 + + for nd_num in nodes: + a = nodes.get(nd_num) + b = nodes.get(nd_num + 1) + un_size = union(a,b) + max_size = max(max_size, un_size) + + return max_size diff --git a/longest-consecutive-sequence/longest-consecutive-sequence.py b/longest-consecutive-sequence/longest-consecutive-sequence.py @@ -0,0 +1,24 @@ +class Solution: + + def search(self, current, count): + if not current in self.num_set: + return count + return self.search(current + 1, count + 1) + + def longestConsecutive(self, nums: List[int]) -> int: + # idea: + # this must be in linear time + # this means we can't sort + # we can use hashmaps though + # with this we could do some sort of key based increment checking, sorta like open addressing + # we'd evict elements as we go so we could achieve O(n) + + max_val = 0 + self.num_set = set(nums) + + for ele in self.num_set: + if ele - 1 in self.num_set: + continue + current = self.search(ele, 0) + max_val = max(current,max_val) + return max_val diff --git a/number-of-provinces/number-of-provinces-v2.cpp b/number-of-provinces/number-of-provinces-v2.cpp @@ -0,0 +1,59 @@ +class Node { + public: + Node* parent = nullptr; + int size = 1; +}; + +Node* find(Node& a){ + if(a.parent == nullptr) { + return &a; + } + auto found = find(*a.parent); + a.parent = found; + return found; +} + +void union_nodes(Node& a, Node& b) { + auto p_a = find(a); + auto p_b = find(b); + if(p_a != p_b) { + if(p_a->size > p_b->size) { + p_b->parent = p_a; + p_a->size += p_b->size; + } else { + p_a->parent = p_b; + p_b->size += p_a->size; + } + } +} + +class Solution { +public: + int findCircleNum(vector<vector<int>>& isConnected) { + + unordered_map<int, Node*> provinces {}; + + for(int i = 0; i < isConnected.size(); ++i) { + Node* node = new Node(); + provinces[i] = node; + } + + for(auto pair: provinces) { + vector<int>& adj = isConnected[pair.first]; + for(int i = 0; i < adj.size(); ++i) { + if(adj[i]) { + union_nodes(*provinces[i], *pair.second); + } + } + } + + unordered_set<Node*> reps {}; + + for(auto pair: provinces) { + auto rep = find(*pair.second); + reps.insert(rep); + } + + return reps.size(); + } +}; diff --git a/number-of-provinces/number-of-provinces.cpp b/number-of-provinces/number-of-provinces.cpp @@ -0,0 +1,51 @@ +class Node { + public: + Node* parent = nullptr; +}; + + +Node* find(Node& a){ + if(a.parent == nullptr) { + return &a; + } + return find(*a.parent); +} + +void union_nodes(Node& a, Node& b) { + auto p_a = find(a); + auto p_b = find(b); + if(p_a != p_b) { + p_b->parent = p_a; + } +} + +class Solution { +public: + int findCircleNum(vector<vector<int>>& isConnected) { + + unordered_map<int, Node*> provinces {}; + + for(int i = 0; i < isConnected.size(); ++i) { + Node* node = new Node(); + provinces[i] = node; + } + + for(auto pair: provinces) { + vector<int>& adj = isConnected[pair.first]; + for(int i = 0; i < adj.size(); ++i) { + if(adj[i]) { + union_nodes(*provinces[i], *pair.second); + } + } + } + + unordered_set<Node*> reps {}; + + for(auto pair: provinces) { + auto rep = find(*pair.second); + reps.insert(rep); + } + + return reps.size(); + } +}; diff --git a/redundant-connection/redundant-connection.cpp b/redundant-connection/redundant-connection.cpp @@ -0,0 +1,82 @@ +class Node { + public: + Node* parent = nullptr; + int identifier; + int size = 1; +}; + +Node* find(Node* a) { + if(a->parent == nullptr) { + return a; + } + else { + auto* rep = find(a->parent); + a->parent = rep; + return rep; + } +} + +// return true if union must be done, false if both have same rep. +bool union_sets(Node* n1,Node* n2) { + auto p_1 = find(n1); + auto p_2 = find(n2); + + if(p_1->identifier == p_2->identifier) { + return false; + } + + if(p_2->size < p_1->size) { + p_2->parent = p_1; + p_1->size += p_2->size; + } else { + p_1->parent = p_2; + p_2->size += p_1->size; + } + return true; +} + +class Solution { +public: + vector<int> findRedundantConnection(vector<vector<int>>& edges) { + // idea: + // - mst where edges are weighted based on position in edges list + // - union find where we join on edges in order of inputs + // - iff union(a,b) is non-changing, put edge a,b in list of un-necessary eles + // - return final element of un-necessary list + + vector<vector<int>> unnecessaryEdges {}; + + // key = index of node + unordered_map<int, Node*> nodes {}; + + for(auto edge: edges) { + if(nodes[edge[0]] == nullptr) { + nodes[edge[0]] = new Node(); + nodes[edge[0]]->identifier = edge[0]; + } + if(nodes[edge[1]] == nullptr) { + nodes[edge[1]] = new Node(); + nodes[edge[1]]->identifier = edge[1]; + } + } + + for(auto edge: edges) { + + auto n1 = nodes[edge[0]]; + auto n2 = nodes[edge[1]]; + + bool joined = union_sets(n1,n2); + if(not joined) { + unnecessaryEdges.push_back(edge); + } + } + + if(unnecessaryEdges.size() > 0) { + return unnecessaryEdges[unnecessaryEdges.size() - 1]; + } + else { + return vector<int>{}; + } + + } +};