The "All Valid Triplets That Can Represent a Country" problem asks you to find all unique triplets in a given array nums
such that each triplet can represent a country based on a specific condition. Typically, the condition is that the sum of the triplet's elements equals a given target
value (sometimes 0, as in the classic 3Sum problem). The solution must:
(nums[i], nums[j], nums[k])
such that i != j != k
and nums[i] + nums[j] + nums[k] == target
.At first glance, you might consider a brute-force approach: check every possible combination of three numbers in the array to see if they sum to the target. However, this quickly becomes inefficient for large arrays, since there are O(n³) possible triplets.
To improve efficiency, it's important to avoid unnecessary checks and duplicate triplets. Sorting the array enables us to use pointers to efficiently check for valid triplets and skip duplicates. This is a common optimization in problems involving unique combinations and sums.
The key insight is to fix one number, then use a two-pointer approach on the rest of the array to find pairs that, together with the fixed number, sum to the target. This reduces the time complexity significantly.
Here is a step-by-step breakdown of the optimized solution:
nums
. This helps with duplicate management and enables the two-pointer technique.nums[i]
).left
(just after i
) and right
(at the end of the array).left < right
:
nums[i] + nums[left] + nums[right]
.left
and right
to skip over duplicate values.left
; if it's more, decrement right
.i
, collecting all unique triplets.We use sorting and pointer movement to efficiently avoid duplicates and unnecessary checks, making the solution much faster than brute force.
Let's walk through an example with nums = [-1, 0, 1, 2, -1, -4]
and target = 0
:
nums
: [-4, -1, -1, 0, 1, 2]
i = 0
(nums[0] = -4
):
left = 1
, right = 5
.-4 + -1 + 2 = -3
(less than 0), so move left
to 2.-4 + -1 + 2 = -3
(again), move left
to 3.left >= right
.i = 1
(nums[1] = -1
):
left = 2
, right = 5
.-1 + -1 + 2 = 0
(found a triplet: [-1, -1, 2]
).left
and right
to skip duplicates.-1 + 0 + 1 = 0
(found [-1, 0, 1]
).i = 2
(nums[2] = -1
), but since it's a duplicate of nums[1]
, skip it.i
values; no new triplets found.
Final result: [[-1, -1, 2], [-1, 0, 1]]
Brute-force approach:
The optimization comes from reducing the number of unnecessary checks and efficiently skipping duplicates.
To find all valid triplets representing a country (i.e., summing to a target value), we use sorting and a two-pointer approach to avoid duplicates and reduce computation. By fixing one number and searching for pairs with two pointers, we achieve an efficient O(n²) solution. The approach is elegant because it combines the strengths of sorting for duplicate management and the two-pointer technique for efficient searching, making it both fast and robust.
def all_valid_triplets(nums, target):
nums.sort()
n = len(nums)
result = []
for i in range(n):
if i > 0 and nums[i] == nums[i-1]:
continue # Skip duplicate 'i'
left, right = i + 1, n - 1
while left < right:
s = nums[i] + nums[left] + nums[right]
if s == target:
result.append([nums[i], nums[left], nums[right]])
left += 1
right -= 1
while left < right and nums[left] == nums[left-1]:
left += 1 # Skip duplicate 'left'
while left < right and nums[right] == nums[right+1]:
right -= 1 # Skip duplicate 'right'
elif s < target:
left += 1
else:
right -= 1
return result
#include <vector>
#include <algorithm>
using namespace std;
vector<vector<int>> allValidTriplets(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int n = nums.size();
vector<vector<int>> result;
for (int i = 0; i < n; ++i) {
if (i > 0 && nums[i] == nums[i-1]) continue;
int left = i + 1, right = n - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == target) {
result.push_back({nums[i], nums[left], nums[right]});
++left; --right;
while (left < right && nums[left] == nums[left-1]) ++left;
while (left < right && nums[right] == nums[right+1]) --right;
} else if (sum < target) {
++left;
} else {
--right;
}
}
}
return result;
}
import java.util.*;
public class Solution {
public List<List<Integer>> allValidTriplets(int[] nums, int target) {
Arrays.sort(nums);
int n = nums.length;
List<List<Integer>> result = new ArrayList<>();
for (int i = 0; i < n; i++) {
if (i > 0 && nums[i] == nums[i-1]) continue;
int left = i + 1, right = n - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == target) {
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
left++; right--;
while (left < right && nums[left] == nums[left-1]) left++;
while (left < right && nums[right] == nums[right+1]) right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
return result;
}
}
function allValidTriplets(nums, target) {
nums.sort((a, b) => a - b);
const n = nums.length;
const result = [];
for (let i = 0; i < n; i++) {
if (i > 0 && nums[i] === nums[i - 1]) continue;
let left = i + 1, right = n - 1;
while (left < right) {
const sum = nums[i] + nums[left] + nums[right];
if (sum === target) {
result.push([nums[i], nums[left], nums[right]]);
left++;
right--;
while (left < right && nums[left] === nums[left - 1]) left++;
while (left < right && nums[right] === nums[right + 1]) right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
return result;
}