|
| 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 'arr'. |
| 7 | +// We traverse 'arr'. With each 'arr[i]', we use two pointers to traverse to find the triplets. |
| 8 | +// Arrays.sort() function has a time complexity of O(n logn). |
| 9 | +// |
| 10 | +// Space Complexity : O(1), |
| 11 | +// as the auxiliary space used is independent of the input 'arr'. |
| 12 | + |
| 13 | +public class ThreeSumWithMultiplicity_Sorting_TwoPointers { |
| 14 | + |
| 15 | + // Approach: |
| 16 | + // Using sorting and two pointers to traverse the sorted array and check each number if they sum to 'target'. |
| 17 | + // Note that, i < j < k and arr[i] + arr[j] + arr[k] == target, |
| 18 | + // do not require the index as the sum is not dependent on the index, so sorting is fine. |
| 19 | + |
| 20 | + public int threeSumMulti(int[] arr, int target) { |
| 21 | + int n = arr.length; |
| 22 | + Arrays.sort(arr); |
| 23 | + long count = 0; |
| 24 | + |
| 25 | + // With each 'i', use two pointers 'j' and 'k' to traverse the remaining numbers to the right of 'i'. |
| 26 | + for (int i = 0; i < n - 2; i++) { |
| 27 | + // If the smallest number is greater than 'target', |
| 28 | + // then the remaining numbers (which are greater) are impossible to sum to be equal to 'target'. |
| 29 | + if (arr[i] + arr[i + 1] + arr[i + 2] > target) break; |
| 30 | + // If the largest number is less than 'target', meaning we need to increase 'i' to get a larger number. |
| 31 | + if (arr[i] + arr[n - 1] + arr[n - 2] < target) continue; |
| 32 | + |
| 33 | + // After the check, traverse with 'j' and 'k' from both ends. |
| 34 | + int j = i + 1; |
| 35 | + int k = n - 1; |
| 36 | + while (j < k) { |
| 37 | + int sum = arr[i] + arr[j] + arr[k]; |
| 38 | + // Move 'j' to right if sum is less than target. |
| 39 | + if (sum < target) j++; |
| 40 | + // Move 'k' to left if sum is greater than target. |
| 41 | + else if (sum > target) k--; |
| 42 | + // If it is equal, keep track of the frequency for both 'arr[j]' and 'arr[k]'. |
| 43 | + else { |
| 44 | + int countJ = 1; |
| 45 | + while (j < k && arr[j] == arr[j + 1]) { |
| 46 | + j++; |
| 47 | + countJ++; |
| 48 | + } |
| 49 | + int countK = 1; |
| 50 | + while (j < k && arr[k] == arr[k - 1]) { |
| 51 | + k--; |
| 52 | + countK++; |
| 53 | + } |
| 54 | + // If both are same, get the geometric sum for 'countJ' + 'countK' - 1. |
| 55 | + // Example: [1,2,2,2,2], target = 5. With arr[i] = 1, arr[j] == arr[k] = 2. |
| 56 | + // Note that the "j < k" will break with 'j' overlapping with 'k'. |
| 57 | + // Thus, 'countJ' = 4 and 'countK' = 1. |
| 58 | + // 'countJ' + 'countK' - 1 = 4, which results in 4 * 3 / 2 = 6 possible combinations. |
| 59 | + if (arr[j] == arr[k]) { |
| 60 | + int frequency = countJ + countK - 1; |
| 61 | + count += (long) frequency * (frequency - 1) / 2; |
| 62 | + } |
| 63 | + // If they are different, the count increase by the multiplication for both. |
| 64 | + // Example: [1,2,2,3,3], target = 6. With arr[i] = 1, arr[j] = 2 and arr[k] = 3. |
| 65 | + // There are 2 * 2 = 4 possible combinations for the 2 and 3. |
| 66 | + else |
| 67 | + count += (long) countJ * countK; |
| 68 | + // Once done, move both pointers to continue check the other numbers. |
| 69 | + j++; |
| 70 | + k--; |
| 71 | + } |
| 72 | + } |
| 73 | + } |
| 74 | + return (int) (count % (1e9 + 7)); |
| 75 | + } |
| 76 | +} |
0 commit comments