|
| 1 | +package com.cheehwatang.leetcode; |
| 2 | + |
| 3 | +import java.util.Arrays; |
| 4 | + |
| 5 | +// Time Complexity : O(n^2), |
| 6 | +// where 'n' is the length of 'nums'. |
| 7 | +// We traverse 'nums' to check each 'nums[i]', with each element we use 2 pointers, |
| 8 | +// thus it is a nested loop, with O(n^2) time complexity. |
| 9 | +// The Arrays.sort() function has a time complexity of O(n logn). |
| 10 | +// |
| 11 | +// Space Complexity : O(1), |
| 12 | +// as the auxiliary space used is independent of the input. |
| 13 | + |
| 14 | +public class ThreeSumClosest { |
| 15 | + |
| 16 | + // Approach: |
| 17 | + // Use sorting and two pointers to search for all the triplets and check for the closest sum to 'target'. |
| 18 | + // For each 'nums[i]' in 'nums', we can check the sum with nums[j] and nums[k] using two pointers, |
| 19 | + // 'left' and 'right' to traverse the remaining numbers. |
| 20 | + // In order to use two pointers in this manner, we have to first sort the array in ascending order. |
| 21 | + // This allows use to check if nums[i] + nums[j] + nums[k] is greater or less than 0. |
| 22 | + // If the sum is less than 'target', then we shift the 'left' pointer to the right. |
| 23 | + // If the sum is greater than 'target', then we shift the 'right' pointer to the left. |
| 24 | + // If we found the sum to be equal to 'target', then we return 'target'. |
| 25 | + // |
| 26 | + // To find the closest number to 'target', we use a variable to keep track and update when found a closer number. |
| 27 | + |
| 28 | + public int threeSumClosest(int[] nums, int target) { |
| 29 | + // Sort the array, and use 2 variables to keep track of the minimum difference and the sum of the triplets. |
| 30 | + Arrays.sort(nums); |
| 31 | + |
| 32 | + int minDiff = Integer.MAX_VALUE; |
| 33 | + int threeSum = 0; |
| 34 | + for (int i = 0; i < nums.length - 2; i++) { |
| 35 | + // If nums[i] is identical with the previous number skip the number to shorten the time. |
| 36 | + if (i > 0 && nums[i] == nums[i - 1]) continue; |
| 37 | + |
| 38 | + // The following 'highSum' and 'lowSum' is additional check to shorten the time. |
| 39 | + // Otherwise, the rest of the code works on their own. |
| 40 | + // |
| 41 | + // The 'highSum' is to check if the largest possible sum for nums[i] is less than the target. |
| 42 | + // Since we have sorted the 'nums', we know all the remaining numbers will be smaller than the 'highSum'. |
| 43 | + // Thus, we can skip the remaining numbers if 'highSum' is lesser than target. |
| 44 | + int highSum = nums[i] + nums[nums.length - 1] + nums[nums.length - 2]; |
| 45 | + if (highSum < target) { |
| 46 | + if (target - highSum < minDiff) { |
| 47 | + threeSum = highSum; |
| 48 | + minDiff = target - highSum; |
| 49 | + } |
| 50 | + continue; |
| 51 | + } |
| 52 | + // The 'lowSum' is to check if the smallest possible sum for nums[i] is greater than the target. |
| 53 | + // Since we have sorted the 'nums', we know all the remaining numbers will be greater than the 'lowSum'. |
| 54 | + // If the 'lowSum' is greater than the target, |
| 55 | + // the remaining numbers, including the subsequent i-th numbers will be greater than the 'lowSum'. |
| 56 | + // Thus, we are sure that 'lowSum' is the closest triplet to 'target', if found. |
| 57 | + int lowSum = nums[i] + nums[i + 1] + nums[i + 2]; |
| 58 | + if (lowSum > target) { |
| 59 | + if (lowSum - target < minDiff) { |
| 60 | + return lowSum; |
| 61 | + } |
| 62 | + } |
| 63 | + |
| 64 | + // After the initial checks, use two pointers, 'left' and 'right'. |
| 65 | + int left = i + 1; |
| 66 | + int right = nums.length - 1; |
| 67 | + while (left < right) { |
| 68 | + int sum = nums[left] + nums[right] + nums[i]; |
| 69 | + int difference = Math.abs(sum - target); |
| 70 | + // If the triplet's 'minDiff' is lesser, then record it as the closest 'threeSum' for now. |
| 71 | + if (difference < minDiff) { |
| 72 | + minDiff = difference; |
| 73 | + threeSum = sum; |
| 74 | + } |
| 75 | + // Otherwise, decrease the 'right' if sum > target, |
| 76 | + if (sum > target) { |
| 77 | + right--; |
| 78 | + while (left < right && nums[right] == nums[right + 1]) right--; |
| 79 | + } |
| 80 | + // and increase 'left' if sum < target. |
| 81 | + else if (sum < target) { |
| 82 | + left++; |
| 83 | + while (left < right && nums[left] == nums[left - 1]) left++; |
| 84 | + } |
| 85 | + // If found sum == target, then it is the closest possible. |
| 86 | + else { |
| 87 | + return sum; |
| 88 | + } |
| 89 | + } |
| 90 | + } |
| 91 | + return threeSum; |
| 92 | + } |
| 93 | +} |
0 commit comments