Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 55 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@
<th>Solution</th>
<th>Topics</th>
</tr>
<tr>
<td align="center">September 1st</td>
<td>16. <a href="https://leetcode.com/problems/3sum-closest/">3Sum Closest</a></td>
<td align="center">$\text{\color{Dandelion}Medium}$</td>
<td align="center">
<a href="https://github.com/cheehwatang/leetcode-java/blob/main/solutions/16.%203Sum%20Closest/ThreeSumClosest.java">Sorting & Two Pointers</a>
</td>
<td align="center">
<a href="#array">Array</a>,
<a href="#sorting">Sorting</a>,
<a href="#two-pointers">Two Pointers</a>
</td>
</tr>
<tr>
<td align="center">August 31st</td>
<td>15. <a href="https://leetcode.com/problems/3sum/">3Sum</a></td>
Expand Down Expand Up @@ -76,18 +89,6 @@
<a href="#string">String</a>
</td>
</tr>
<tr>
<td align="center">August 27th</td>
<td>3. <a href="https://leetcode.com/problems/longest-substring-without-repeating-characters/">Longest Substring Without Repeating Characters</a></td>
<td align="center">$\text{\color{Dandelion}Medium}$</td>
<td align="center">
<a href="https://github.com/cheehwatang/leetcode-java/blob/main/solutions/3.%20Longest%20Substring%20Without%20Repeating%20Characters/LongestSubstringWithoutRepeatingCharacters.java">Sliding Window</a>
</td>
<td align="center">
<a href="#sliding-window">Sliding Window</a>,
<a href="#string">String</a>
</td>
</tr>
</table>
</br>
<hr>
Expand Down Expand Up @@ -178,6 +179,20 @@
</td>
<td></td>
</tr>
<tr>
<td align="center">16</td>
<td><a href="https://leetcode.com/problems/3sum-closest/">3Sum Closest</a></td>
<td align="center">
<a href="https://github.com/cheehwatang/leetcode-java/blob/main/solutions/16.%203Sum%20Closest/ThreeSumClosest.java">Java</a>
</td>
<td align="center">$\text{\color{Dandelion}Medium}$</td>
<td align="center">
<a href="#array">Array</a>,
<a href="#sorting">Sorting</a>,
<a href="#two-pointers">Two Pointers</a>
</td>
<td></td>
</tr>
<tr>
<td align="center">26</td>
<td><a href="https://leetcode.com/problems/remove-duplicates-from-sorted-array/">Remove Duplicates from Sorted Array</a></td>
Expand Down Expand Up @@ -7286,6 +7301,20 @@
</td>
<td></td>
</tr>
<tr>
<td align="center">16</td>
<td><a href="https://leetcode.com/problems/3sum-closest/">3Sum Closest</a></td>
<td align="center">
<a href="https://github.com/cheehwatang/leetcode-java/blob/main/solutions/16.%203Sum%20Closest/ThreeSumClosest.java">Java</a>
</td>
<td align="center">$\text{\color{Dandelion}Medium}$</td>
<td align="center">
<a href="#array">Array</a>,
<a href="#sorting">Sorting</a>,
<a href="#two-pointers">Two Pointers</a>
</td>
<td></td>
</tr>
<tr>
<td align="center">49</td>
<td><a href="https://leetcode.com/problems/group-anagrams/">Group Anagrams</a></td>
Expand Down Expand Up @@ -9189,6 +9218,20 @@
</td>
<td></td>
</tr>
<tr>
<td align="center">16</td>
<td><a href="https://leetcode.com/problems/3sum-closest/">3Sum Closest</a></td>
<td align="center">
<a href="https://github.com/cheehwatang/leetcode-java/blob/main/solutions/16.%203Sum%20Closest/ThreeSumClosest.java">Java</a>
</td>
<td align="center">$\text{\color{Dandelion}Medium}$</td>
<td align="center">
<a href="#array">Array</a>,
<a href="#sorting">Sorting</a>,
<a href="#two-pointers">Two Pointers</a>
</td>
<td></td>
</tr>
<tr>
<td align="center">19</td>
<td><a href="https://leetcode.com/problems/remove-nth-node-from-end-of-list/">Remove Nth Node From End of List</a></td>
Expand Down
93 changes: 93 additions & 0 deletions solutions/16. 3Sum Closest/ThreeSumClosest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.cheehwatang.leetcode;

import java.util.Arrays;

// Time Complexity : O(n^2),
// where 'n' is the length of 'nums'.
// We traverse 'nums' to check each 'nums[i]', with each element we use 2 pointers,
// thus it is a nested loop, with O(n^2) time complexity.
// The Arrays.sort() function has a time complexity of O(n logn).
//
// Space Complexity : O(1),
// as the auxiliary space used is independent of the input.

public class ThreeSumClosest {

// Approach:
// Use sorting and two pointers to search for all the triplets and check for the closest sum to 'target'.
// For each 'nums[i]' in 'nums', we can check the sum with nums[j] and nums[k] using two pointers,
// 'left' and 'right' to traverse the remaining numbers.
// In order to use two pointers in this manner, we have to first sort the array in ascending order.
// This allows use to check if nums[i] + nums[j] + nums[k] is greater or less than 0.
// If the sum is less than 'target', then we shift the 'left' pointer to the right.
// If the sum is greater than 'target', then we shift the 'right' pointer to the left.
// If we found the sum to be equal to 'target', then we return 'target'.
//
// To find the closest number to 'target', we use a variable to keep track and update when found a closer number.

public int threeSumClosest(int[] nums, int target) {
// Sort the array, and use 2 variables to keep track of the minimum difference and the sum of the triplets.
Arrays.sort(nums);

int minDiff = Integer.MAX_VALUE;
int threeSum = 0;
for (int i = 0; i < nums.length - 2; i++) {
// If nums[i] is identical with the previous number skip the number to shorten the time.
if (i > 0 && nums[i] == nums[i - 1]) continue;

// The following 'highSum' and 'lowSum' is additional check to shorten the time.
// Otherwise, the rest of the code works on their own.
//
// The 'highSum' is to check if the largest possible sum for nums[i] is less than the target.
// Since we have sorted the 'nums', we know all the remaining numbers will be smaller than the 'highSum'.
// Thus, we can skip the remaining numbers if 'highSum' is lesser than target.
int highSum = nums[i] + nums[nums.length - 1] + nums[nums.length - 2];
if (highSum < target) {
if (target - highSum < minDiff) {
threeSum = highSum;
minDiff = target - highSum;
}
continue;
}
// The 'lowSum' is to check if the smallest possible sum for nums[i] is greater than the target.
// Since we have sorted the 'nums', we know all the remaining numbers will be greater than the 'lowSum'.
// If the 'lowSum' is greater than the target,
// the remaining numbers, including the subsequent i-th numbers will be greater than the 'lowSum'.
// Thus, we are sure that 'lowSum' is the closest triplet to 'target', if found.
int lowSum = nums[i] + nums[i + 1] + nums[i + 2];
if (lowSum > target) {
if (lowSum - target < minDiff) {
return lowSum;
}
}

// After the initial checks, use two pointers, 'left' and 'right'.
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
int sum = nums[left] + nums[right] + nums[i];
int difference = Math.abs(sum - target);
// If the triplet's 'minDiff' is lesser, then record it as the closest 'threeSum' for now.
if (difference < minDiff) {
minDiff = difference;
threeSum = sum;
}
// Otherwise, decrease the 'right' if sum > target,
if (sum > target) {
right--;
while (left < right && nums[right] == nums[right + 1]) right--;
}
// and increase 'left' if sum < target.
else if (sum < target) {
left++;
while (left < right && nums[left] == nums[left - 1]) left++;
}
// If found sum == target, then it is the closest possible.
else {
return sum;
}
}
}
return threeSum;
}
}