Given an integer array nums.Return all triplets such that:
Notice that the solution set must not contain duplicate triplets. One element can be a part of multiple triplets. The output and the triplets can be returned in any order.
Input: nums = [2, -2, 0, 3, -3, 5]
Output: [[-2, 0, 2], [-3, -2, 5], [-3, 0, 3]]
Explanation: nums[1] + nums[2] + nums[0] = 0
nums[4] + nums[1] + nums[5] = 0
nums[4] + nums[2] + nums[3] = 0
Input: nums = [2, -1, -1, 3, -1]
Output: [[-1, -1, 2]]
Explanation: nums[1] + nums[2] + nums[0] = 0
Note that we have used two -1s as they are separate elements with different indexes
But we have not used the -1 at index 4 as that would create a duplicate triplet
Input: nums = [8, -6, 5, 4]
(Give answer with the output and triplets sorted in ascending order)
The most naive idea is to check all possible triplets using 3 loops and among them, consider the ones whose sum is equal to the given target 0.
Before taking them as the answer, sort the triplets in ascending order so as to consider only the unique triplets.
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
//Function to find triplets having sum equals to target
vector<vector<int>> threeSum(vector<int>& nums) {
// Set to store unique triplets
set<vector<int>> tripletSet;
int n = nums.size();
// Check all possible triplets
for (int i = 0; i < n - 2; i++) {
for (int j = i + 1; j < n - 1; j++) {
for (int k = j + 1; k < n; k++) {
if (nums[i] + nums[j] + nums[k] == 0) {
// Found a triplet that sums up to target
vector<int> temp = {nums[i], nums[j], nums[k]};
/* Sort the triplet to ensure
uniqueness when storing in set*/
sort(temp.begin(), temp.end());
tripletSet.insert(temp);
}
}
}
}
// Convert set to vector (unique triplets)
vector<vector<int>> ans(tripletSet.begin(), tripletSet.end());
//Return the ans
return ans;
}
};
int main() {
vector<int> nums = {-1, 0, 1, 2, -1, -4};
// Create an instance of Solution class
Solution sol;
vector<vector<int>> ans = sol.threeSum(nums);
// Print the result
for (auto& triplet : ans) {
cout << "[";
for (auto& num : triplet) {
cout << num << " ";
}
cout << "] ";
}
cout << "\n";
return 0;
}
import java.util.*;
class Solution {
//Function to find triplets having sum equals to target
public List<List<Integer>> threeSum(int[] nums) {
// Set to store unique triplets
Set<List<Integer>> tripletSet = new HashSet<>();
int n = nums.length;
// Check all possible triplets
for (int i = 0; i < n - 2; i++) {
for (int j = i + 1; j < n - 1; j++) {
for (int k = j + 1; k < n; k++) {
if (nums[i] + nums[j] + nums[k] == 0) {
// Found a triplet that sums up to target
List<Integer> temp = new ArrayList<>();
temp.add(nums[i]);
temp.add(nums[j]);
temp.add(nums[k]);
/* Sort the triplet to ensure
uniqueness when storing in set*/
Collections.sort(temp);
tripletSet.add(temp);
}
}
}
}
// Convert set to list of lists (unique triplets)
List<List<Integer>> ans = new ArrayList<>(tripletSet);
//Return the ans
return ans;
}
}
public class Main {
public static void main(String[] args) {
int[] nums = {-1, 0, 1, 2, -1, -4};
// Create an instance of Solution class
Solution sol = new Solution();
List<List<Integer>> ans = sol.threeSum(nums);
// Print the result
for (List<Integer> triplet : ans) {
System.out.print("[");
for (int num : triplet) {
System.out.print(num + " ");
}
System.out.print("] ");
}
System.out.println();
}
}
from typing import List
class Solution:
#Function to find triplets having sum equals to target
def threeSum(self, nums: List[int]) -> List[List[int]]:
# Set to store unique triplets
triplet_set = set()
n = len(nums)
# Check all possible triplets
for i in range(n - 2):
for j in range(i + 1, n - 1):
for k in range(j + 1, n):
if nums[i] + nums[j] + nums[k] == 0:
# Found a triplet that sums up to target
temp = [nums[i], nums[j], nums[k]]
""" Sort the triplet to ensure
uniqueness when storing in set"""
temp.sort()
triplet_set.add(tuple(temp))
# Convert set to list of lists (unique triplets)
ans = [list(triplet) for triplet in triplet_set]
#Return the ans
return ans
if __name__ == "__main__":
nums = [-1, 0, 1, 2, -1, -4]
# Create an instance of Solution class
sol = Solution()
ans = sol.threeSum(nums)
# Print the result
for triplet in ans:
print(f"[{', '.join(map(str, triplet))}]")
class Solution {
// Function to find triplets having sum equals to target
threeSum(nums) {
// Set to store unique triplets
let tripletSet = new Set();
let n = nums.length;
// Check all possible triplets
for (let i = 0; i < n - 2; i++) {
for (let j = i + 1; j < n - 1; j++) {
for (let k = j + 1; k < n; k++) {
if (nums[i] + nums[j] + nums[k] === 0) {
// Found a triplet that sums up to target
let temp = [nums[i], nums[j], nums[k]];
/* Sort the triplet to ensure
uniqueness when storing in set*/
temp.sort((a, b) => a - b);
tripletSet.add(temp.join(','));
}
}
}
}
// Convert set to array of arrays (unique triplets)
let ans = Array.from(tripletSet).map(triplet => triplet.split(',').map(num => parseInt(num)));
// Return the ans
return ans;
}
}
// Main function to test the solution
let nums = [-1, 0, 1, 2, -1, -4];
// Create an instance of Solution class
let sol = new Solution();
let ans = sol.threeSum(nums);
// Print the result
ans.forEach(triplet => {
console.log(`[${triplet.join(', ')}]`);
});
The better approach uses simple mathematics where some calculative parameter is taken in RHS(right hand side) to compute the result.
For example if a + b + c = 0, then a + b = -c. Similar idea is used here.
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
// Function to find triplets having sum equals to target
vector<vector<int>> threeSum(vector<int>& nums) {
// Set to store unique triplets
set<vector<int>> tripletSet;
int n = nums.size();
// Check all possible triplets
for (int i = 0; i < n; i++) {
// Set to store elements seen so far in the loop
set<int> hashset;
for (int j = i + 1; j < n; j++) {
// Calculate the 3rd element needed to reach target
int third = - (nums[i] + nums[j]);
/* Find if third element exists in
hashset (complements seen so far)*/
if (hashset.find(third) != hashset.end()) {
// Found a triplet that sums up to target
vector<int> temp = {nums[i], nums[j], third};
/* Sort the triplet to ensure
uniqueness when storing in set*/
sort(temp.begin(), temp.end());
tripletSet.insert(temp);
}
/* Insert the current element
into hashset for future checks*/
hashset.insert(nums[j]);
}
}
// Convert set to vector (unique triplets)
vector<vector<int>> ans(tripletSet.begin(), tripletSet.end());
//Return the ans
return ans;
}
};
int main() {
vector<int> nums = {-1, 0, 1, 2, -1, -4};
// Create an instance of Solution class
Solution sol;
vector<vector<int>> ans = sol.threeSum(nums);
// Print the result
for (auto& triplet : ans) {
cout << "[";
for (auto& num : triplet) {
cout << num << " ";
}
cout << "] ";
}
cout << "\n";
return 0;
}
import java.util.*;
class Solution {
// Function to find triplets having sum equals to 0
public List<List<Integer>> threeSum(int[] nums) {
// Set to store unique triplets
Set<List<Integer>> tripletSet = new HashSet<>();
int n = nums.length;
// Check all possible triplets
for (int i = 0; i < n; i++) {
// Set to store elements seen so far in the loop
Set<Integer> hashset = new HashSet<>();
for (int j = i + 1; j < n; j++) {
// Calculate the 3rd element needed to reach 0
int third = - (nums[i] + nums[j]);
/* Find if third element exists in
hashset (complements seen so far)*/
if (hashset.contains(third)) {
// Found a triplet that sums up to target
List<Integer> temp = new ArrayList<>();
temp.add(nums[i]);
temp.add(nums[j]);
temp.add(third);
/* Sort the triplet to ensure
uniqueness when storing in set*/
Collections.sort(temp);
tripletSet.add(temp);
}
/* Insert the current element
into hashset for future checks*/
hashset.add(nums[j]);
}
}
// Convert set to list of lists (unique triplets)
List<List<Integer>> ans = new ArrayList<>(tripletSet);
//Return the ans
return ans;
}
public static void main(String[] args) {
int[] nums = {-1, 0, 1, 2, -1, -4};
// Create an instance of Solution class
Solution sol = new Solution();
List<List<Integer>> ans = sol.threeSum(nums);
// Print the result
for (List<Integer> triplet : ans) {
System.out.print("[");
for (int num : triplet) {
System.out.print(num + " ");
}
System.out.print("] ");
}
System.out.println();
}
}
from typing import List
class Solution:
# Function to find triplets having sum equals to 0
def threeSum(self, nums: List[int]) -> List[List[int]]:
# Set to store unique triplets
triplet_set = set()
n = len(nums)
# Check all possible triplets
for i in range(n):
# Set to store elements seen so far in the loop
hashset = set()
for j in range(i + 1, n):
# Calculate the 3rd element needed to reach target
third = - (nums[i] + nums[j])
""" Find if third element exists in
hashset (complements seen so far)"""
if third in hashset:
# Found a triplet that sums up to target
temp = [nums[i], nums[j], third]
""" Sort the triplet to ensure
uniqueness when storing in set"""
temp.sort()
triplet_set.add(tuple(temp))
""" Insert the current element
into hashset for future checks"""
hashset.add(nums[j])
# Convert set to list of lists (unique triplets)
ans = [list(triplet) for triplet in triplet_set]
#Return the ans
return ans
if __name__ == "__main__":
nums = [-1, 0, 1, 2, -1, -4]
# Create an instance of Solution class
sol = Solution()
ans = sol.threeSum(nums)
# Print the result
for triplet in ans:
print(f"[{', '.join(map(str, triplet))}]")
class Solution {
// Function to find triplets having sum equals to 0
threeSum(nums) {
// Set to store unique triplets
let tripletSet = new Set();
let n = nums.length;
// Check all possible triplets
for (let i = 0; i < n; i++) {
// Set to store elements seen so far in the loop
let hashset = new Set();
for (let j = i + 1; j < n; j++) {
// Calculate the 3rd element needed to reach target
let third = - (nums[i] + nums[j]);
/* Find if third element exists in
hashset (complements seen so far)*/
if (hashset.has(third)) {
// Found a triplet that sums up to target
let temp = [nums[i], nums[j], third];
/* Sort the triplet to ensure
uniqueness when storing in set*/
temp.sort((a, b) => a - b);
tripletSet.add(JSON.stringify(temp));
}
/* Insert the current element
into hashset for future checks*/
hashset.add(nums[j]);
}
}
// Convert set to list of lists (unique triplets)
let ans = Array.from(tripletSet).map(triplet => JSON.parse(triplet));
//Return the ans
return ans;
}
}
// Main function to test the solution
let nums = [-1, 0, 1, 2, -1, -4];
// Create an instance of Solution class
let sol = new Solution();
let ans = sol.threeSum(nums);
// Print the result
ans.forEach(triplet => {
console.log(`[${triplet.join(', ')}]`);
});
Imagine you're organizing a dinner party and you want to create a balanced meal with three different ingredients that together have zero net calories.
First task would be to list all your ingredients by their calorie values and sort them. Then, for each ingredient, try to find two other ingredients from the remaining list that, when combined, balance the calories back to zero.
Start with one ingredient and use two pointers, one starting from the left (beginning of the list) and the other from the right (end of the list). By adjusting these pointers, check if the three chosen ingredients balance to zero calories. If they do, you have a balanced meal! Continue this process, ensuring that the same combination of ingredients more than once is not picked.
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
// Function to find triplets having sum equals to target
vector<vector<int>> threeSum(vector<int>& nums) {
// Vector to store the triplets that sum up to target
vector<vector<int>> ans;
int n = nums.size();
// Sort the input array nums
sort(nums.begin(), nums.end());
// Iterate through the array to find triplets
for (int i = 0; i < n; i++) {
// Skip duplicates
if (i > 0 && nums[i] == nums[i - 1]) continue;
// Two pointers approach
int j = i + 1;
int k = n - 1;
while (j < k) {
int sum = nums[i] + nums[j] + nums[k];
if (sum < 0) {
j++;
} else if (sum > 0) {
k--;
} else {
// Found a triplet that sums up to target
vector<int> temp = {nums[i], nums[j], nums[k]};
ans.push_back(temp);
// Skip duplicates
j++;
k--;
while (j < k && nums[j] == nums[j - 1]) j++;
while (j < k && nums[k] == nums[k + 1]) k--;
}
}
}
return ans;
}
};
int main() {
vector<int> nums = {-1, 0, 1, 2, -1, -4};
// Create an instance of Solution class
Solution sol;
vector<vector<int>> ans = sol.threeSum(nums);
// Print the result
for (auto& triplet : ans) {
cout << "[";
for (auto& num : triplet) {
cout << num << " ";
}
cout << "] ";
}
cout << "\n";
return 0;
}
import java.util.*;
class Solution {
// Function to find triplets having sum equals to target
public List<List<Integer>> threeSum(int[] nums) {
// List to store the triplets that sum up to target
List<List<Integer>> ans = new ArrayList<>();
int n = nums.length;
// Sort the input array nums
Arrays.sort(nums);
// Iterate through the array to find triplets
for (int i = 0; i < n; i++) {
// Skip duplicates
if (i > 0 && nums[i] == nums[i - 1]) continue;
// Two pointers approach
int j = i + 1;
int k = n - 1;
while (j < k) {
int sum = nums[i] + nums[j] + nums[k];
if (sum < 0) {
j++;
} else if (sum > 0) {
k--;
} else {
// Found a triplet that sums up to target
List<Integer> temp = new ArrayList<>();
temp.add(nums[i]);
temp.add(nums[j]);
temp.add(nums[k]);
ans.add(temp);
// Skip duplicates
j++;
k--;
while (j < k && nums[j] == nums[j - 1]) j++;
while (j < k && nums[k] == nums[k + 1]) k--;
}
}
}
return ans;
}
}
public class Main {
public static void main(String[] args) {
int[] nums = {-1, 0, 1, 2, -1, -4};
// Create an instance of Solution class
Solution sol = new Solution();
List<List<Integer>> ans = sol.threeSum(nums);
// Print the result
for (List<Integer> triplet : ans) {
System.out.print("[");
for (int num : triplet) {
System.out.print(num + " ");
}
System.out.print("] ");
}
System.out.println();
}
}
from typing import List
class Solution:
# Function to find triplets having sum equals to target
def threeSum(self, nums: List[int]) -> List[List[int]]:
# List to store the triplets that sum up to target
ans = []
n = len(nums)
# Sort the input array nums
nums.sort()
# Iterate through the array to find triplets
for i in range(n):
# Skip duplicates
if i > 0 and nums[i] == nums[i - 1]:
continue
# Two pointers approach
j = i + 1
k = n - 1
while j < k:
sum_val = nums[i] + nums[j] + nums[k]
if sum_val < 0:
j += 1
elif sum_val > 0:
k -= 1
else:
# Found a triplet that sums up to target
temp = [nums[i], nums[j], nums[k]]
ans.append(temp)
# Skip duplicates
j += 1
k -= 1
while j < k and nums[j] == nums[j - 1]:
j += 1
while j < k and nums[k] == nums[k + 1]:
k -= 1
return ans
if __name__ == "__main__":
nums = [-1, 0, 1, 2, -1, -4]
# Create an instance of Solution class
sol = Solution()
ans = sol.threeSum(nums)
# Print the result
for triplet in ans:
print(f"[{', '.join(map(str, triplet))}]")
class Solution {
// Function to find triplets having sum equals to target
threeSum(nums) {
// Array to store the triplets that sum up to target
let ans = [];
// Sort the input array nums
nums.sort((a, b) => a - b);
let n = nums.length;
// Iterate through the array to find triplets
for (let i = 0; i < n; i++) {
// Skip duplicates
if (i > 0 && nums[i] === nums[i - 1]) continue;
// Two pointers approach
let j = i + 1;
let k = n - 1;
while (j < k) {
let sumVal = nums[i] + nums[j] + nums[k];
if (sumVal < 0) {
j++;
} else if (sumVal > 0) {
k--;
} else {
// Found a triplet that sums up to target
let temp = [nums[i], nums[j], nums[k]];
ans.push(temp);
// Skip duplicates
j++;
k--;
while (j < k && nums[j] === nums[j - 1]) j++;
while (j < k && nums[k] === nums[k + 1]) k--;
}
}
}
return ans;
}
}
// Main function to test the Solution class
function main() {
let nums = [-1, 0, 1, 2, -1, -4];
// Create an instance of Solution class
let sol = new Solution();
let ans = sol.threeSum(nums);
// Print the result
ans.forEach(triplet => {
console.log(`[${triplet.join(', ')}]`);
});
}
// Invoke the main function
main();
Q: How do we avoid duplicate triplets?
A: Skip duplicate values of nums[i] while iterating. Skip duplicate values of nums[left] and nums[right] during the two-pointer traversal.
Q: Why sort the array?
A: Sorting allows: Efficient identification of duplicates by comparing adjacent elements. Simplification of the two-pointer logic, as the relationship between pointer movements and the sum becomes predictable.
Q: What if the input array is unsorted?
A: Sorting is part of the solution and is necessary for efficient implementation. It adds O(nlogn) complexity, which is negligible compared to the O(n2) time required for finding triplets.
Q: How would you modify the algorithm to find all unique triplets with a sum equal to a different target?
A: Instead of finding triplets that sum to 0: Look for triplets that sum to a given target t. Use the same two-pointer approach, with nums[left]+nums[right]=t−nums[i].