Given an array arr[] of integers and an integer target. Return all possible unique triplets [a, b, c] in the array whose sum is equal to the given target. Each triplet must be arranged in non-decreasing order (a ≤ b ≤ c).
The triplets may be returned in any order. The driver will sort the output before comparison.
Examples:
Input: arr[] = [12, 3, 6, 1, 6, 9], target = 24
Output: [[3, 9, 12], [6, 6, 12]]
Explanation: Triplets with sum 24 are [3, 9, 12] and [6, 6, 12].Input: arr[] = [1, 1, 1, 1], target = 3
Output: [[1, 1, 1]]
Explanation: Triplets with sum 3 are [1, 1, 1].Input: arr[] = [10, 12, 10, 15], target = 32
Output: [[10, 10, 12]]
Explanation: Triplets with sum 32 are [10, 10, 12].
Table of Content
[Naive Approach] Exploring all triplets - O(n ^ 3) Time and O(1) Space
The idea is to use three nested loops to generate all possible triplets, then check if their sum is equal to the target.
Working of Approach:
- Use three nested loops to select indices i, j, and k such that i < j < k.
- If arr[i] + arr[j] + arr[k] == target, create the triplet and sort it.
- Use find() to check whether this sorted triplet already exists in res.
- If it is new, add it to the result and finally return all unique triplets.
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> threeSum(vector<int> &arr, int target)
{
vector<vector<int>> res;
int n = arr.size();
// Generating all possible triplets
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
for (int k = j + 1; k < n; k++)
{
if (arr[i] + arr[j] + arr[k] == target)
{
vector<int> curr = {arr[i], arr[j], arr[k]};
sort(curr.begin(), curr.end());
// If triplet doesn't exist in the res, then only insert it.
if (find(res.begin(), res.end(), curr) == res.end())
res.push_back(curr);
}
}
}
}
return res;
}
int main()
{
vector<int> arr = {12, 3, 6, 1, 6, 9};
int target = 24;
vector<vector<int>> ans = threeSum(arr, target);
cout << "[";
for (int i = 0; i < ans.size(); i++)
{
cout << "[";
for (int j = 0; j < ans[i].size(); j++)
{
cout << ans[i][j];
if (j + 1 < ans[i].size())
cout << ", ";
}
cout << "]";
if (i + 1 < ans.size())
cout << ", ";
}
cout << "]";
return 0;
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class GFG {
public static ArrayList<ArrayList<Integer> >
threeSum(int[] arr, int target)
{
ArrayList<ArrayList<Integer> > res
= new ArrayList<>();
int n = arr.length;
// Generating all possible triplets
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
for (int k = j + 1; k < n; k++) {
if (arr[i] + arr[j] + arr[k]
== target) {
ArrayList<Integer> curr
= new ArrayList<>(Arrays.asList(
arr[i], arr[j], arr[k]));
Collections.sort(curr);
// If triplet doesn't exist in the
// res, then only insert it.
if (!res.contains(curr))
res.add(curr);
}
}
}
}
return res;
}
public static void main(String[] args)
{
int[] arr = { 12, 3, 6, 1, 6, 9 };
int target = 24;
ArrayList<ArrayList<Integer> > ans
= threeSum(arr, target);
System.out.print("[");
for (int i = 0; i < ans.size(); i++) {
System.out.print("[");
for (int j = 0; j < ans.get(i).size(); j++) {
System.out.print(ans.get(i).get(j));
if (j + 1 < ans.get(i).size())
System.out.print(", ");
}
System.out.print("]");
if (i + 1 < ans.size())
System.out.print(", ");
}
System.out.print("]");
}
}
def threeSum(arr: list[int], target: int) -> list[list[int]]:
res = []
n = len(arr)
# Generating all possible triplets
for i in range(n):
for j in range(i + 1, n):
for k in range(j + 1, n):
if arr[i] + arr[j] + arr[k] == target:
curr = [arr[i], arr[j], arr[k]]
curr.sort()
# If triplet doesn't exist in the res, then only insert it.
if curr not in res:
res.append(curr)
return res
if __name__ == "__main__":
arr = [12, 3, 6, 1, 6, 9]
target = 24
ans = threeSum(arr, target)
print('[', end='')
for i in range(len(ans)):
print('[', end='')
for j in range(len(ans[i])):
print(ans[i][j], end='')
if j + 1 < len(ans[i]):
print(', ', end='')
print(']', end='')
if i + 1 < len(ans):
print(', ', end='')
print(']')
using System;
using System.Collections.Generic;
using System.Linq;
public class GFG {
public static List<List<int> > threeSum(int[] arr,
int target)
{
List<List<int> > res = new List<List<int> >();
int n = arr.Length;
// Generating all possible triplets
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
for (int k = j + 1; k < n; k++) {
if (arr[i] + arr[j] + arr[k]
== target) {
List<int> curr
= new List<int>{ arr[i], arr[j],
arr[k] };
curr.Sort();
// If triplet doesn't exist in the
// res, then only insert it.
if (!res.Any(r => r.SequenceEqual(
curr)))
res.Add(curr);
}
}
}
}
return res;
}
public static void Main()
{
int[] arr = { 12, 3, 6, 1, 6, 9 };
int target = 24;
List<List<int> > ans = threeSum(arr, target);
Console.Write("[");
for (int i = 0; i < ans.Count; i++) {
Console.Write("[");
for (int j = 0; j < ans[i].Count; j++) {
Console.Write(ans[i][j]);
if (j + 1 < ans[i].Count)
Console.Write(", ");
}
Console.Write("]");
if (i + 1 < ans.Count)
Console.Write(", ");
}
Console.Write("]");
}
}
function threeSum(arr, target) {
let res = [];
let n = arr.length;
// Generating all possible triplets
for (let i = 0; i < n; i++)
{
for (let j = i + 1; j < n; j++)
{
for (let k = j + 1; k < n; k++)
{
if (arr[i] + arr[j] + arr[k] === target)
{
let curr = [arr[i], arr[j], arr[k]];
curr.sort((a, b) => a - b);
// If triplet doesn't exist in the res, then only insert it.
let found = false;
for (let l = 0; l < res.length; l++)
{
if (arraysEqual(res[l], curr))
{
found = true;
break;
}
}
if (!found)
res.push(curr);
}
}
}
}
return res;
}
function arraysEqual(a, b) {
if (a === b) return true;
if (a == null || b == null) return false;
if (a.length!== b.length) return false;
for (let i = 0; i < a.length; ++i) {
if (a[i]!== b[i]) return false;
}
return true;
}
function main() {
let arr = [12, 3, 6, 1, 6, 9];
let target = 24;
let ans = threeSum(arr, target);
console.log('[');
for (let i = 0; i < ans.length; i++)
{
console.log('[');
for (let j = 0; j < ans[i].length; j++)
{
console.log(ans[i][j]);
if (j + 1 < ans[i].length)
console.log(', ');
}
console.log(']');
if (i + 1 < ans.length)
console.log(', ');
}
console.log(']');
}
main();
Output
[[3, 9, 12], [6, 6, 12]]
[Better Approach] Using Hashing - O(n ^ 2 log n) Time and O(n) Space
The idea is to fix one element and use a hash set to find the required complement for the other two elements. For every pair, calculate target - arr[i] - arr[j] and check whether it has already appeared in the hash set.
Working of Approach:
- Fix each element arr[i] and traverse the remaining elements using j.
- For every arr[j], calculate the required complement = target - arr[i] - arr[j].
- Check the complement in the hash set; if found, a valid triplet is formed.
- Sort each triplet and store it in a set to remove duplicate triplets.
#include <bits/stdc++.h>
using namespace std;
vector<vector<int>> threeSum(vector<int> &arr, int target)
{
int n = arr.size();
// Store unique triplets in a set to avoid duplicates.
set<vector<int>> resSet;
// Fix the first element and find the remaining two elements.
for (int i = 0; i < n; i++)
{
unordered_set<int> s;
// Traverse the remaining elements.
for (int j = i + 1; j < n; j++)
{
int complement = target - arr[i] - arr[j];
// If complement exists, we have found a valid triplet.
if (s.find(complement) != s.end())
{
vector<int> curr = {arr[i], arr[j], complement};
// Sort the triplet to handle duplicate combinations.
sort(curr.begin(), curr.end());
// Insert the triplet into the set.
resSet.insert(curr);
}
// Store the current element for future pairs.
s.insert(arr[j]);
}
}
// Convert the set of triplets into a vector.
return vector<vector<int>>(resSet.begin(), resSet.end());
}
int main()
{
vector<int> arr = {12, 3, 6, 1, 6, 9};
int target = 24;
vector<vector<int>> ans = threeSum(arr, target);
cout << "[";
for (int i = 0; i < ans.size(); i++)
{
cout << "[";
for (int j = 0; j < ans[i].size(); j++)
{
cout << ans[i][j];
if (j + 1 < ans[i].size())
cout << ", ";
}
cout << "]";
if (i + 1 < ans.size())
cout << ", ";
}
cout << "]";
return 0;
}
import java.util.*;
class GFG {
public static ArrayList<ArrayList<Integer> >
threeSum(int[] arr, int target)
{
int n = arr.length;
// Store unique triplets in a set to avoid
// duplicates.
Set<List<Integer> > resSet
= new TreeSet<>((a, b) -> {
for (int i = 0; i < a.size(); i++) {
int cmp = Integer.compare(a.get(i),
b.get(i));
if (cmp != 0)
return cmp;
}
return 0;
});
// Fix the first element and find the remaining two
// elements.
for (int i = 0; i < n; i++) {
HashSet<Integer> s = new HashSet<>();
// Traverse the remaining elements.
for (int j = i + 1; j < n; j++) {
int complement = target - arr[i] - arr[j];
// If complement exists, we have found a
// valid triplet.
if (s.contains(complement)) {
ArrayList<Integer> curr
= new ArrayList<>(Arrays.asList(
arr[i], arr[j], complement));
// Sort the triplet to handle duplicate
// combinations.
Collections.sort(curr);
// Insert the triplet into the set.
resSet.add(curr);
}
// Store the current element for future
// pairs.
s.add(arr[j]);
}
}
// Convert the set of triplets into the required
// result.
ArrayList<ArrayList<Integer> > res
= new ArrayList<>();
for (List<Integer> triplet : resSet)
res.add(new ArrayList<>(triplet));
return res;
}
public static void main(String[] args)
{
int[] arr = { 12, 3, 6, 1, 6, 9 };
int target = 24;
ArrayList<ArrayList<Integer> > ans
= threeSum(arr, target);
System.out.println(ans);
}
}
def threeSum(arr, target):
n = len(arr)
# Store unique triplets in a set to avoid duplicates.
resSet = set()
# Fix the first element and find the remaining two elements.
for i in range(n):
s = set()
# Traverse the remaining elements.
for j in range(i + 1, n):
complement = target - arr[i] - arr[j]
# If complement exists, we have found a valid triplet.
if complement in s:
curr = [arr[i], arr[j], complement]
# Sort the triplet to handle duplicate combinations.
curr.sort()
# Insert the triplet into the set.
resSet.add(tuple(curr))
# Store the current element for future pairs.
s.add(arr[j])
# Convert the set of triplets into a list.
return [list(triplet) for triplet in resSet]
if __name__ == '__main__':
arr = [12, 3, 6, 1, 6, 9]
target = 24
ans = threeSum(arr, target)
print('[')
for i in range(len(ans)):
print('[')
for j in range(len(ans[i])):
print(ans[i][j], end='')
if j + 1 < len(ans[i]):
print(', ', end='')
print(']')
if i + 1 < len(ans):
print(', ', end='')
print(']')
using System;
using System.Collections.Generic;
using System.Linq;
public class GFG {
public static List<List<int> > threeSum(int[] arr,
int target)
{
int n = arr.Length;
// Store unique triplets in a set to avoid
// duplicates.
HashSet<string> seen = new HashSet<string>();
List<List<int> > res = new List<List<int> >();
// Fix the first element and find the remaining two
// elements.
for (int i = 0; i < n; i++) {
HashSet<int> s = new HashSet<int>();
// Traverse the remaining elements.
for (int j = i + 1; j < n; j++) {
int complement = target - arr[i] - arr[j];
// If complement exists, we have found a
// valid triplet.
if (s.Contains(complement)) {
List<int> curr
= new List<int>{ arr[i], arr[j],
complement };
// Sort the triplet to handle duplicate
// combinations.
curr.Sort();
string key = string.Join(",", curr);
// Insert the triplet only if it is
// unique.
if (seen.Add(key))
res.Add(curr);
}
// Store the current element for future
// pairs.
s.Add(arr[j]);
}
}
// Sort the result for the same ordering as the C++
// set.
res.Sort((a, b) => {
for (int i = 0; i < a.Count; i++) {
if (a[i] != b[i])
return a[i].CompareTo(b[i]);
}
return 0;
});
return res;
}
public static void Main()
{
int[] arr = { 12, 3, 6, 1, 6, 9 };
int target = 24;
List<List<int> > ans = threeSum(arr, target);
Console.Write("[");
for (int i = 0; i < ans.Count; i++) {
Console.Write("[");
for (int j = 0; j < ans[i].Count; j++) {
Console.Write(ans[i][j]);
if (j + 1 < ans[i].Count)
Console.Write(", ");
}
Console.Write("]");
if (i + 1 < ans.Count)
Console.Write(", ");
}
Console.Write("]");
}
}
function threeSum(arr, target)
{
let n = arr.length;
// Store unique triplets in a set to avoid duplicates.
let resSet = new Set();
let res = [];
// Fix the first element and find the remaining two
// elements.
for (let i = 0; i < n; i++) {
let s = new Set();
// Traverse the remaining elements.
for (let j = i + 1; j < n; j++) {
let complement = target - arr[i] - arr[j];
// If complement exists, we have found a valid
// triplet.
if (s.has(complement)) {
let curr = [ arr[i], arr[j], complement ];
// Sort the triplet to handle duplicate
// combinations.
curr.sort((a, b) => a - b);
let key = curr.join(",");
// Insert the triplet only if it is unique.
if (!resSet.has(key)) {
resSet.add(key);
res.push(curr);
}
}
// Store the current element for future pairs.
s.add(arr[j]);
}
}
// Sort the result for the same ordering as the C++ set.
res.sort((a, b) => {
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i])
return a[i] - b[i];
}
return 0;
});
return res;
}
// Driver Code
let arr = [ 12, 3, 6, 1, 6, 9 ];
let target = 24;
let ans = threeSum(arr, target);
console.log(ans);
Output
[[3, 9, 12], [6, 6, 12]]
[Expected Approach] Using Two Pointers Technique - O(n ^ 2) Time and O(1) Space
The idea is to sort the array and use the two-pointer technique to find all triplets with the given target sum. Fix the first element and use two pointers to search for the remaining two elements while skipping duplicates.
- If sum == target, store the triplet and skip duplicates.
- If sum < target, move the left pointer forward.
- If sum > target, move the right pointer backward.
Let us understand with an example:
Input: arr[] = [12, 3, 6, 1, 6, 9], target = 24
- Sort the array: [1, 3, 6, 6, 9, 12].
- Fix 1 and use j = 1, k = 5; the sum remains less than 24, so move j forward.
- Fix 3 with j = 2, k = 5; when 3 + 9 + 12 = 24, store [3, 9, 12].
- Move both pointers and continue searching for other triplets.
- Fix 6 with j = 3, k = 5; 6 + 6 + 12 = 24, so store [6, 6, 12].
- Skip duplicate values and return [[3, 9, 12], [6, 6, 12]].
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> threeSum(vector<int> &arr, int target)
{
vector<vector<int>> res;
int n = arr.size();
// Sort the array to apply the two-pointer technique
sort(arr.begin(), arr.end());
// Fix the first element of the triplet
for (int i = 0; i < n - 2; i++)
{
// Skip duplicate values for the first element
// to avoid duplicate triplets
if (i > 0 && arr[i] == arr[i - 1])
continue;
int j = i + 1;
int k = n - 1;
// Find the remaining two elements using two pointers
while (j < k)
{
int sum = arr[i] + arr[j] + arr[k];
if (sum == target)
{
// Valid triplet found
res.push_back({arr[i], arr[j], arr[k]});
j++;
k--;
// Skip duplicate values for the second element
while (j < k && arr[j] == arr[j - 1])
j++;
// Skip duplicate values for the third element
while (j < k && arr[k] == arr[k + 1])
k--;
}
// Increase the sum by moving the left pointer
else if (sum < target)
{
j++;
}
// Decrease the sum by moving the right pointer
else
{
k--;
}
}
}
return res;
}
int main()
{
vector<int> arr = {12, 3, 6, 1, 6, 9};
int target = 24;
vector<vector<int>> ans = threeSum(arr, target);
cout << "[";
for (int i = 0; i < ans.size(); i++)
{
cout << "[";
for (int j = 0; j < ans[i].size(); j++)
{
cout << ans[i][j];
if (j + 1 < ans[i].size())
cout << ", ";
}
cout << "]";
if (i + 1 < ans.size())
cout << ", ";
}
cout << "]";
return 0;
}
import java.util.*;
class GFG {
public static ArrayList<ArrayList<Integer> >
threeSum(int[] arr, int target)
{
ArrayList<ArrayList<Integer> > res
= new ArrayList<>();
int n = arr.length;
// Sort the array to apply the two-pointer technique
Arrays.sort(arr);
// Fix the first element of the triplet
for (int i = 0; i < n - 2; i++) {
// Skip duplicate values for the first element
// to avoid duplicate triplets
if (i > 0 && arr[i] == arr[i - 1])
continue;
int j = i + 1;
int k = n - 1;
// Find the remaining two elements using two
// pointers
while (j < k) {
int sum = arr[i] + arr[j] + arr[k];
if (sum == target) {
// Valid triplet found
ArrayList<Integer> curr
= new ArrayList<>();
curr.add(arr[i]);
curr.add(arr[j]);
curr.add(arr[k]);
res.add(curr);
j++;
k--;
// Skip duplicate values for the second
// element
while (j < k && arr[j] == arr[j - 1])
j++;
// Skip duplicate values for the third
// element
while (j < k && arr[k] == arr[k + 1])
k--;
}
// Increase the sum by moving the left
// pointer
else if (sum < target) {
j++;
}
// Decrease the sum by moving the right
// pointer
else {
k--;
}
}
}
return res;
}
public static void main(String[] args)
{
int[] arr = { 12, 3, 6, 1, 6, 9 };
int target = 24;
ArrayList<ArrayList<Integer> > ans
= threeSum(arr, target);
System.out.println(ans);
}
}
from typing import List
def threeSum(arr: List[int], target: int) -> List[List[int]]:
res = []
n = len(arr)
# Sort the array to apply the two-pointer technique
arr.sort()
# Fix the first element of the triplet
for i in range(n - 2):
# Skip duplicate values for the first element
# to avoid duplicate triplets
if i > 0 and arr[i] == arr[i - 1]:
continue
j = i + 1
k = n - 1
# Find the remaining two elements using two pointers
while j < k:
sum = arr[i] + arr[j] + arr[k]
if sum == target:
# Valid triplet found
res.append([arr[i], arr[j], arr[k]])
j += 1
k -= 1
# Skip duplicate values for the second element
while j < k and arr[j] == arr[j - 1]:
j += 1
# Skip duplicate values for the third element
while j < k and arr[k] == arr[k + 1]:
k -= 1
elif sum < target:
# Increase the sum by moving the left pointer
j += 1
else:
# Decrease the sum by moving the right pointer
k -= 1
return res
if __name__ == "__main__":
arr = [12, 3, 6, 1, 6, 9]
target = 24
ans = threeSum(arr, target)
print('[')
for i in range(len(ans)):
print('[')
for j in range(len(ans[i])):
print(ans[i][j], end='')
if j + 1 < len(ans[i]):
print(', ', end='')
print(']')
if i + 1 < len(ans):
print(', ')
print(']')
using System;
using System.Collections.Generic;
class GFG {
public static List<List<int> > threeSum(int[] arr,
int target)
{
List<List<int> > res = new List<List<int> >();
int n = arr.Length;
// Sort the array to apply the two-pointer technique
Array.Sort(arr);
// Fix the first element of the triplet
for (int i = 0; i < n - 2; i++) {
// Skip duplicate values for the first element
// to avoid duplicate triplets
if (i > 0 && arr[i] == arr[i - 1])
continue;
int j = i + 1;
int k = n - 1;
// Find the remaining two elements using two
// pointers
while (j < k) {
int sum = arr[i] + arr[j] + arr[k];
if (sum == target) {
// Valid triplet found
List<int> curr
= new List<int>{ arr[i], arr[j],
arr[k] };
res.Add(curr);
j++;
k--;
// Skip duplicate values for the second
// element
while (j < k && arr[j] == arr[j - 1])
j++;
// Skip duplicate values for the third
// element
while (j < k && arr[k] == arr[k + 1])
k--;
}
// Increase the sum by moving the left
// pointer
else if (sum < target) {
j++;
}
// Decrease the sum by moving the right
// pointer
else {
k--;
}
}
}
return res;
}
public static void Main()
{
int[] arr = { 12, 3, 6, 1, 6, 9 };
int target = 24;
List<List<int> > ans = threeSum(arr, target);
Console.Write("[");
for (int i = 0; i < ans.Count; i++) {
Console.Write("[");
for (int j = 0; j < ans[i].Count; j++) {
Console.Write(ans[i][j]);
if (j + 1 < ans[i].Count)
Console.Write(", ");
}
Console.Write("]");
if (i + 1 < ans.Count)
Console.Write(", ");
}
Console.Write("]");
}
}
function threeSum(arr, target)
{
let res = [];
let n = arr.length;
// Sort the array to apply the two-pointer technique
arr.sort((a, b) => a - b);
// Fix the first element of the triplet
for (let i = 0; i < n - 2; i++) {
// Skip duplicate values for the first element
// to avoid duplicate triplets
if (i > 0 && arr[i] === arr[i - 1])
continue;
let j = i + 1;
let k = n - 1;
// Find the remaining two elements using two
// pointers
while (j < k) {
let sum = arr[i] + arr[j] + arr[k];
if (sum === target) {
// Valid triplet found
res.push([ arr[i], arr[j], arr[k] ]);
j++;
k--;
// Skip duplicate values for the second
// element
while (j < k && arr[j] === arr[j - 1])
j++;
// Skip duplicate values for the third
// element
while (j < k && arr[k] === arr[k + 1])
k--;
}
// Increase the sum by moving the left pointer
else if (sum < target) {
j++;
}
// Decrease the sum by moving the right pointer
else {
k--;
}
}
}
return res;
}
// Driver Code
let arr = [ 12, 3, 6, 1, 6, 9 ];
let target = 24;
let ans = threeSum(arr, target);
console.log("[");
for (let i = 0; i < ans.length; i++) {
console.log("[");
for (let j = 0; j < ans[i].length; j++) {
console.log(ans[i][j]);
if (j + 1 < ans[i].length)
console.log(", ");
}
console.log("]");
if (i + 1 < ans.length)
console.log(", ");
}
console.log("]");
Output
[[3, 9, 12], [6, 6, 12]]