python coding test course, union find

Hello! In this post, we will explore the Union-Find algorithm and solve algorithmic problems using it. The Union-Find is a very useful data structure for managing disjoint sets, providing the ability to quickly determine the connectivity of multiple items and to merge sets.

What is Union-Find?

Union-Find consists of two main functions:

  • Union: An operation that merges the sets containing two elements
  • Find: An operation that finds which set a specific element belongs to

Through these two operations, we can easily manage the relationships between various elements and efficiently solve complex connectivity problems. It is particularly useful in graph problems and network connectivity issues.

How Union-Find Works

Union-Find mainly maximizes efficiency using two techniques:

1. Path Compression

When performing a Find operation, the path is compressed to reduce the height of the tree. This decreases the time complexity when performing multiple Find operations.

2. Union by Rank

While performing the Union operation, we consider the ‘rank’ (height) of the sets, attaching the lower rank set to the higher rank set. This method also reduces the depth of the trees, enhancing operational efficiency.

Problem: Counting the Number of Connected Components

Consider the following problem:

Given n nodes and m edges, find the number of connected components of nodes. The nodes are represented by integers from 0 to n-1, and edge information is given in the form of (a, b).

Input Example

    5 3
    0 1
    1 2
    3 4
    

Output Example

    2
    

Solution Process

To solve this problem, we will use the Union-Find data structure to organize the relationships between each node. We will follow these steps:

Step 1: Initialize the Parent Array

Each node is initialized to have itself as its parent. In other words, we create a parent array and set each node to point to itself.

    parent = [0, 1, 2, 3, 4]  # Initialized according to the number of nodes
    

Step 2: Perform Union Operations

Based on the given edge information, we connect the nodes through Union operations. This combines connected sets into one.

Step 3: Count Connected Sets Using Find Operations

By performing Find operations on each node, we check which set they belong to and count the number of unique root nodes before printing the result.

Implementation

Now, let’s implement the above steps in Python code.

    class UnionFind:
        def __init__(self, size):
            self.parent = list(range(size))
            self.rank = [1] * size
        
        def find(self, p):
            if self.parent[p] != p:
                # Path compression
                self.parent[p] = self.find(self.parent[p])
            return self.parent[p]
        
        def union(self, p, q):
            rootP = self.find(p)
            rootQ = self.find(q)
            
            if rootP != rootQ:
                # Union by rank
                if self.rank[rootP] > self.rank[rootQ]:
                    self.parent[rootQ] = rootP
                elif self.rank[rootP] < self.rank[rootQ]:
                    self.parent[rootP] = rootQ
                else:
                    self.parent[rootQ] = rootP
                    self.rank[rootP] += 1

    # Usage Example
    def count_connected_components(n, edges):
        uf = UnionFind(n)
        
        # Perform Union with edge information
        for u, v in edges:
            uf.union(u, v)
        
        # Count the number of unique roots and return the number of connected components
        root_set = set(uf.find(i) for i in range(n))
        return len(root_set)

    # Input handling
    n = 5
    edges = [(0, 1), (1, 2), (3, 4)]
    print(count_connected_components(n, edges))  # Output: 2
    

Interpreting Results

When executing the above code, it outputs 2. This indicates that there are two sets of nodes that are connected in the given graph.

Time Complexity Analysis

When using Union-Find, the time complexity of each operation approaches O(α(n)), where α is the inverse Ackermann function. Since this function grows extremely slowly, we can consider it to take close to constant time in practical terms.

Conclusion

In this post, we examined the Union-Find data structure and methods for solving problems using it. We confirmed that Union-Find can efficiently solve complex connectivity problems, encouraging you to practice various applications.

Thank you!