Minimize Hamming Distance After Swap Operations
Minimize Hamming Distance After Swap Operations solution for LeetCode 1722, with the key idea, complexity breakdown, and working code in Java, C++, JavaScript, TypeScript, C, Go, and Rust.
Solve on LeetCode ↗Minimize Hamming Distance After Swap Operations
What the problem is really asking
We are given two arrays, source and target.
Some index pairs are swappable. The important detail is that swaps can be done any number of times and in any order.
So if index 0 can swap with 1, and index 1 can swap with 4, then indices 0, 1, and 4 form one connected group. Inside that group, values from source can be rearranged freely.
The goal is to minimize how many positions still differ from target.
Key insight
This is not really a swap simulation problem.
It is a connected components problem.
Every connected component of indices behaves like one bucket:
- the values from
sourceinside that component can be permuted however we want - values cannot move from one component to another
- for each component, we only care about matching frequencies
So for each component, count the values available in source.
Then scan target. If the component still has the needed value, use it. Otherwise, this index must contribute 1 to the Hamming distance.
Approach
Use Union Find.
- Create one DSU node for every index.
- Union every pair from
allowedSwaps. - For every index
i, find its component root and countsource[i]inside that root. - Scan
target. - For every index
i, check whether its component has one unusedtarget[i]. - If yes, consume that value.
- If no, increase the answer.
Code Solution
Switch between languages
import java.util.HashMap;
import java.util.Map;
class Solution {
private int[] parent;
private int[] rank;
public int minimumHammingDistance(int[] source, int[] target, int[][] allowedSwaps) {
int n = source.length;
parent = new int[n];
rank = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
}
for (int[] swap : allowedSwaps) {
union(swap[0], swap[1]);
}
Map<Integer, Map<Integer, Integer>> counts = new HashMap<>();
for (int i = 0; i < n; i++) {
int root = find(i);
counts.putIfAbsent(root, new HashMap<>());
Map<Integer, Integer> freq = counts.get(root);
freq.put(source[i], freq.getOrDefault(source[i], 0) + 1);
}
int answer = 0;
for (int i = 0; i < n; i++) {
int root = find(i);
Map<Integer, Integer> freq = counts.get(root);
int available = freq.getOrDefault(target[i], 0);
if (available > 0) {
freq.put(target[i], available - 1);
} else {
answer++;
}
}
return answer;
}
private int find(int node) {
if (parent[node] != node) {
parent[node] = find(parent[node]);
}
return parent[node];
}
private void union(int a, int b) {
int rootA = find(a);
int rootB = find(b);
if (rootA == rootB) {
return;
}
if (rank[rootA] < rank[rootB]) {
parent[rootA] = rootB;
} else if (rank[rootA] > rank[rootB]) {
parent[rootB] = rootA;
} else {
parent[rootB] = rootA;
rank[rootA]++;
}
}
}Dry run
Take:
source = [1, 2, 3, 4]
target = [2, 1, 4, 5]
allowedSwaps = [[0, 1], [2, 3]]
The allowed swaps create two components:
- component A: indices
0, 1 - component B: indices
2, 3
For component A:
- source values are
{1, 2} - target wants
{2, 1} - both can be matched
For component B:
- source values are
{3, 4} - target wants
{4, 5} 4can be matched5cannot be matched
So the minimum Hamming distance is 1.
Why Union Find fits perfectly
Allowed swaps are edges between indices.
If two indices are connected by a path, we can move values across that path using repeated swaps. That means the exact edge order does not matter after we build the connected components.
Union Find gives us those components efficiently, even when n and allowedSwaps.length are both up to 100000.
Common mistakes
1. Simulating the swaps
There can be too many possible swap sequences. We only need to know which indices are connected.
2. Comparing whole-array frequencies
Overall frequencies are not enough. Values can only move inside their own connected component.
3. Forgetting duplicate values
Each matched value can be used only once.
That is why we decrement the frequency after matching a target value.
Complexity
Let n be the length of the arrays and m be the number of allowed swaps.
Time Complexity: O((n + m) * alpha(n))
Here alpha(n) is the inverse Ackermann function from DSU operations, which is effectively constant in practice.
Space Complexity: O(n)
We store the DSU arrays and the frequency counts for component values.
7 DP Patterns > 100 LeetCode Questions
Most DP questions are repeated ideas. Stop treating DP like chaos. Learn the 7 repeatable patterns that unlock most placement-level questions.