BackeasyGraphsAccenturePaytm

Frequency Window Constraint Optimizer 3 Solution

Problem Statement

You are tasked with optimizing a distributed sensor network where N nodes are initially isolated. The network receives a sequence of M connection requests, each specifying two node indices to be linked. Using the Union-Find (Disjoint Set Union) data structure, process these connections to maintain the connectivity state of the network. For each connection request, determine if the two nodes already belong to the same connected component. If they do, the connection is redundant and should be ignored; otherwise, merge the components. Your goal is to count the total number of redundant connections encountered during the processing of the sequence.

Input consists of an integer N representing the number of nodes (labeled 1 to N) and an integer M representing the number of connection requests. This is followed by M pairs of integers, where each pair (u, v) denotes a request to connect node u and node v. Output a single integer representing the count of redundant connections.

The Union-Find structure must support two primary operations: find (to determine the root of a node's component) and union (to merge two components). Path compression and union by rank are recommended to ensure efficient performance. A connection is considered redundant if the find operation for both nodes returns the same root before the union operation is attempted.

Example 1
Input
N = 4, M = 4, connections = [[1, 2], [2, 3], [3, 4], [1, 4]]
Output
1

Explanation: 1. Process [1, 2]: find(1)=1, find(2)=2. Different roots. Union them. Redundant count = 0. 2. Process [2, 3]: find(2)=1, find(3)=3. Different roots. Union them. Redundant count = 0. 3. Process [3, 4]: find(3)=1, find(4)=4. Different roots. Union them. Redundant count = 0. 4. Process [1, 4]: find(1)=1, find(4)=1. Same root. Connection is redundant. Redundant count = 1. Final output: 1.

Example 2
Input
N = 5, M = 3, connections = [[1, 2], [3, 4], [5, 5]]
Output
1

Explanation: 1. Process [1, 2]: find(1)=1, find(2)=2. Different roots. Union them. Redundant count = 0. 2. Process [3, 4]: find(3)=3, find(4)=4. Different roots. Union them. Redundant count = 0. 3. Process [5, 5]: find(5)=5, find(5)=5. Same root. Connection is redundant (self-loop). Redundant count = 1. Final output: 1.

Example 3
Input
N = 3, M = 2, connections = [[1, 2], [2, 3]]
Output
0

Explanation: 1. Process [1, 2]: find(1)=1, find(2)=2. Different roots. Union them. Redundant count = 0. 2. Process [2, 3]: find(2)=1, find(3)=3. Different roots. Union them. Redundant count = 0. Final output: 0.

Constraints

  • 1 <= N <= 10^5
  • 0 <= M <= 10^5
  • 1 <= u, v <= N
  • u != v for all connections (no self-loops in input, but logic must handle them if present)
Live Compiler1 Free Run Available
Loading Editor...
Test Cases & Output
Click "Run" to test your 1 free compile trial!

🚀 Practice this problem

Run code, get AI hints & track streak

Sign Up Free

Frequency Window Constraint Optimizer 3 — Problem Statement & Solution Guide

GraphsEasyUnion-Find Disjoint Set
TimeO(N + M·α(N)) ≈ O(N + M)
|
SpaceO(N)

Problem Description

You are tasked with optimizing a distributed sensor network where N nodes are initially isolated. The network receives a sequence of M connection requests, each specifying two node indices to be linked. Using the Union-Find (Disjoint Set Union) data structure, process these connections to maintain the connectivity state of the network. For each connection request, determine if the two nodes already belong to the same connected component. If they do, the connection is redundant and should be ignored; otherwise, merge the components. Your goal is to count the total number of redundant connections encountered during the processing of the sequence.

Input consists of an integer N representing the number of nodes (labeled 1 to N) and an integer M representing the number of connection requests. This is followed by M pairs of integers, where each pair (u, v) denotes a request to connect node u and node v. Output a single integer representing the count of redundant connections.

The Union-Find structure must support two primary operations: find (to determine the root of a node's component) and union (to merge two components). Path compression and union by rank are recommended to ensure efficient performance. A connection is considered redundant if the find operation for both nodes returns the same root before the union operation is attempted.

DSA Pattern Breakdown

DSA Pattern Breakdown

"Frequency Window Constraint Optimizer 3"

easy

WHY DOES IT MATTER?

Connectivity queries appear in virtually every large‑scale system—social networks, network routing, clustering, and version control. Efficiently maintaining dynamic connectivity without recomputing the whole graph each time is crucial for performance and scalability.

OPTIMIZATION CHALLENGE

The breakthrough is realizing that you don't need to store the entire adjacency structure; you only need a parent pointer per node and a size/rank metric. Path compression collapses deep trees on the fly, turning a potentially O(N) find into an almost constant operation.

REAL-WORLD CONNECTION

Think of a distributed file system where each server holds a replica of a file. When two servers synchronize, they form a logical group. DSU is analogous to a leader election protocol that quickly tells whether two servers already belong to the same replication group.

During an interview, implement DSU with two small helper functions—find with path compression and union with rank/size. Keep the code clean, test edge cases (self‑union, duplicate edges), and always return the result of find before union to answer the connectivity query.

COMPLEXITY AT A GLANCE

⏱ Time:O(N + M·α(N)) ≈ O(N + M)
💾 Space:O(N)

Core Theory — Why This Approach?

The Union‑Find (Disjoint Set Union, DSU) data structure maintains a partition of a set into disjoint subsets and supports two operations in near‑constant amortized time: **find** – returns the representative (root) of the subset containing an element, and **union** – merges two subsets. By representing each node as a leaf in a forest and using *path compression* during find, the depth of any tree becomes almost flat, guaranteeing an inverse‑Ackermann bound (α(N)) per operation. A naive adjacency‑list or BFS/DFS after each request would require O(N+M) per query, exploding to O(N·M) for large inputs, which is infeasible for N, M up to 10⁵ or 10⁶. The optimal paradigm leverages DSU’s ability to answer connectivity queries online while incrementally building the graph, turning the problem into a sequence of union and find calls that run in essentially O(1) amortized time.

When processing a connection request (u, v), we first **find** the roots of u and v. If the roots match, the nodes are already in the same component, and we output "YES" (or similar). Otherwise we **union** the two roots, optionally using union‑by‑size/rank to keep trees shallow. This approach scales linearly with the number of requests, O(N + M α(N)), and uses only O(N) auxiliary space for parent and size arrays. The elegance of DSU lies in its simplicity and the powerful theoretical guarantee that even massive streams of union‑find operations remain fast.

Interview Questions on This Problem

Q1How would you modify the DSU to also support querying the size of the connected component containing a given node?

Maintain an auxiliary size array where size[root] stores the number of elements in that component. During union, attach the smaller tree under the larger and update size[newRoot] = size[root1] + size[root2]. The size query then becomes a simple find followed by a lookup of size[root].

Q2Explain why path compression and union by rank together give an almost constant amortized time per operation.

Path compression flattens the tree by making every node on the find path point directly to the root, while union by rank ensures the shallower tree becomes a child of the deeper one, limiting height growth. Together they bound the tree height to O(α(N)), where α is the inverse Ackermann function, which grows slower than any practical logarithm, making each operation effectively O(1) on average.

Q3In a distributed sensor network, connections may arrive out of order or be duplicated. How would you handle duplicate connection requests using DSU?

Before performing a union, execute find on both endpoints. If the roots are identical, the nodes are already connected, so you simply record the answer (e.g., "already connected") and skip the union. This naturally deduplicates repeated edges without extra bookkeeping.

Examples

Example 1

Input

N = 4, M = 4, connections = [[1, 2], [2, 3], [3, 4], [1, 4]]

Output

1

Explanation: 1. Process [1, 2]: find(1)=1, find(2)=2. Different roots. Union them. Redundant count = 0. 2. Process [2, 3]: find(2)=1, find(3)=3. Different roots. Union them. Redundant count = 0. 3. Process [3, 4]: find(3)=1, find(4)=4. Different roots. Union them. Redundant count = 0. 4. Process [1, 4]: find(1)=1, find(4)=1. Same root. Connection is redundant. Redundant count = 1. Final output: 1.

Example 2

Input

N = 5, M = 3, connections = [[1, 2], [3, 4], [5, 5]]

Output

1

Explanation: 1. Process [1, 2]: find(1)=1, find(2)=2. Different roots. Union them. Redundant count = 0. 2. Process [3, 4]: find(3)=3, find(4)=4. Different roots. Union them. Redundant count = 0. 3. Process [5, 5]: find(5)=5, find(5)=5. Same root. Connection is redundant (self-loop). Redundant count = 1. Final output: 1.

Example 3

Input

N = 3, M = 2, connections = [[1, 2], [2, 3]]

Output

0

Explanation: 1. Process [1, 2]: find(1)=1, find(2)=2. Different roots. Union them. Redundant count = 0. 2. Process [2, 3]: find(2)=1, find(3)=3. Different roots. Union them. Redundant count = 0. Final output: 0.

Constraints

  • 1 <= N <= 10^5
  • 0 <= M <= 10^5
  • 1 <= u, v <= N
  • u != v for all connections (no self-loops in input, but logic must handle them if present)

Optimal Approach & Strategy

Use a DSU with path compression and union‑by‑rank/size, performing a find for each endpoint and union only when they differ, achieving amortized O(1) per request.

Brute Force Approach

Run a fresh BFS/DFS from one node of each request to see if the other node is reachable, which costs O(N+M) per query.

Verified Code Solutions

JavaScript Solution
Time: O(N + M·α(N)) ≈ O(N + M)
function solution(nums) {
   let freqMap = new Map();
   let sum = 0;
   for (let num of nums) {
       if (freqMap.has(num)) {
           let freq = freqMap.get(num);
           freqMap.set(num, freq + 1);
       } else {
           freqMap.set(num, 1);
       }
   }
   for (let [num, freq] of freqMap) {
       sum += num * freq;
   }
   return sum;
}

Asked in Top Tech Interviews

AccenturePaytm

Solve in Interative Editor

Ready to test your code? Open our built-in compiler, run custom test suites, and see detailed complexity analysis reports instantly.