Using Nested Loops for Generating Pairs
Discover how to use nested loops to generate all possible pairs in an array, a fundamental technique for combinatorial problems.
The Combinatorial Brute Force
One of the most common applications of a nested loop is generating pairs. The classic problem is the "Two Sum" problem: Find two numbers in an array that add up to a specific target.
The Naive Pair Generation
To check every possible combination of two elements, you fix one element (using an outer loop) and compare it to every other element (using an inner loop).
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length; j++) {
if (array[i] + array[j] == target) {
return true;
}
}
}
The Duplicate Work Problem
The loop above works, but it does unnecessary work.
- It compares an element with itself (when
i == j). - It checks pairs twice. It checks
array[0]witharray[1], and later it checksarray[1]witharray[0].
The Optimized Nested Loop
To generate unique pairs without repetition and without self-comparison, the inner loop must always start one position ahead of the outer loop.
for (int i = 0; i < array.length - 1; i++) {
for (int j = i + 1; j < array.length; j++) {
if (array[i] + array[j] == target) {
return true;
}
}
}
By setting int j = i + 1, the inner loop only looks at the elements to the right of i.
Time Complexity
Even though the inner loop runs fewer times as i increases, the time complexity is mathematically O(N^2 / 2). In Big O notation, we drop the division, leaving us with an O(N^2) worst-case scenario.
The Takeaway
Starting the inner loop at i + 1 is a mandatory design pattern when generating unique combinations or pairs. It prevents redundant checks and prevents an element from pairing with itself.
Use a nested loop where the outer loop tracks index 'i', and the inner loop starts at index 'j = i + 1'.
It ensures you do not pair an element with itself, and it prevents generating redundant, mirrored pairs (e.g., checking [0,1] and then [1,0]).
Although the inner loop shrinks, the overall time complexity is still bounded by O(N^2) Quadratic Time.
Yes. For problems like Two Sum, utilizing a Hash Map allows you to check for complementary pairs in O(N) linear time.
You would use three nested loops (i, j = i+1, k = j+1). This results in an O(N^3) time complexity.
