💡 Sorting the array allows us to use two pointers to efficiently count valid triplets without enumerating all, drastically improving performance.
Intuition
Fix one element, then use two pointers to find pairs that together with the fixed element have sum less than target.
Algorithm
- Sort the array.
- Initialize count to 0.
- For each index i from 0 to n-3, fix nums[i].
- Set two pointers: left = i+1, right = n-1.
- While left < right:
- Calculate current sum = nums[i] + nums[left] + nums[right].
- If sum < target, all elements between left and right form valid triplets with i, so add (right - left) to count and move left forward.
- Else, move right backward to reduce sum.
- Return count.
💡 The key insight is that when sum < target, all pairs between left and right pointers are valid, so we count them at once.
def threeSumSmaller(nums, target):
nums.sort()
count = 0
n = len(nums)
for i in range(n - 2):
left, right = i + 1, n - 1
while left < right:
curr_sum = nums[i] + nums[left] + nums[right]
if curr_sum < target:
count += right - left
left += 1
else:
right -= 1
return count
# Driver code
if __name__ == '__main__':
print(threeSumSmaller([-2, 0, 1, 3], 2)) # Output: 2
Line Notes
nums.sort()Sorting enables two-pointer technique
for i in range(n - 2)Fix first element of triplet
left, right = i + 1, n - 1Initialize two pointers for remaining elements
while left < rightLoop until pointers meet
curr_sum = nums[i] + nums[left] + nums[right]Calculate current triplet sum
if curr_sum < targetIf sum less than target, all pairs between left and right are valid
count += right - leftAdd all valid pairs at once
left += 1Move left pointer forward to find new pairs
else: right -= 1Sum too large, move right pointer backward to reduce sum
return countReturn total count of valid triplets
import java.util.Arrays;
public class Solution {
public static int threeSumSmaller(int[] nums, int target) {
Arrays.sort(nums);
int count = 0;
int n = nums.length;
for (int i = 0; i < n - 2; i++) {
int left = i + 1, right = n - 1;
while (left < right) {
int currSum = nums[i] + nums[left] + nums[right];
if (currSum < target) {
count += right - left;
left++;
} else {
right--;
}
}
}
return count;
}
public static void main(String[] args) {
int[] nums = {-2, 0, 1, 3};
System.out.println(threeSumSmaller(nums, 2)); // Output: 2
}
}
Line Notes
Arrays.sort(nums);Sort array to apply two-pointer approach
for (int i = 0; i < n - 2; i++)Fix first element
int left = i + 1, right = n - 1;Initialize two pointers
while (left < right)Loop until pointers cross
int currSum = nums[i] + nums[left] + nums[right];Calculate sum of triplet
if (currSum < target)If sum less than target, count all pairs between left and right
count += right - left;Add number of valid pairs at once
left++;Move left pointer forward
else { right--; }Sum too large, move right pointer backward
return count;Return total count
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int threeSumSmaller(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int count = 0;
int n = nums.size();
for (int i = 0; i < n - 2; i++) {
int left = i + 1, right = n - 1;
while (left < right) {
int currSum = nums[i] + nums[left] + nums[right];
if (currSum < target) {
count += right - left;
left++;
} else {
right--;
}
}
}
return count;
}
int main() {
vector<int> nums = {-2, 0, 1, 3};
cout << threeSumSmaller(nums, 2) << endl; // Output: 2
return 0;
}
Line Notes
sort(nums.begin(), nums.end());Sort array for two-pointer technique
for (int i = 0; i < n - 2; i++)Fix first element
int left = i + 1, right = n - 1;Initialize two pointers
while (left < right)Loop until pointers meet
int currSum = nums[i] + nums[left] + nums[right];Calculate current triplet sum
if (currSum < target)If sum less than target, count all pairs between left and right
count += right - left;Add all valid pairs at once
left++;Move left pointer forward
else { right--; }Sum too large, move right pointer backward
return count;Return total count
function threeSumSmaller(nums, target) {
nums.sort((a, b) => a - b);
let count = 0;
const n = nums.length;
for (let i = 0; i < n - 2; i++) {
let left = i + 1, right = n - 1;
while (left < right) {
const currSum = nums[i] + nums[left] + nums[right];
if (currSum < target) {
count += right - left;
left++;
} else {
right--;
}
}
}
return count;
}
// Test
console.log(threeSumSmaller([-2, 0, 1, 3], 2)); // Output: 2
Line Notes
nums.sort((a, b) => a - b);Sort array to enable two-pointer approach
for (let i = 0; i < n - 2; i++)Fix first element
let left = i + 1, right = n - 1;Initialize two pointers
while (left < right)Loop until pointers meet
const currSum = nums[i] + nums[left] + nums[right];Calculate sum of triplet
if (currSum < target)If sum less than target, count all pairs between left and right
count += right - left;Add all valid pairs at once
left++;Move left pointer forward
else { right--; }Sum too large, move right pointer backward
return count;Return total count
TimeO(n^2)
SpaceO(1) or O(n) depending on sorting implementation
Sorting takes O(n log n). The outer loop runs n times, and the inner two-pointer loop runs O(n) total per iteration, resulting in O(n^2) time.
💡 For n=1000, this means about 1 million operations, which is efficient enough for interviews.
Interview Verdict: Accepted
This approach is efficient and commonly accepted in interviews for this problem.