classSolution { // public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
// int ans = 0; // a simple way is use 4-level embedded looping, but would result in runtime exceed // for (int i = 0; i < nums1.length; i++) { // for (int j = 0; j < nums2.length; j++) { // for (int k = 0; k < nums3.length; k++) { // for (int l = 0; l < nums4.length; l++) { // if(nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0) { // ans ++; // } // } // } // } // }
// divide 4 arrays into 2 partitions which decrease the complexity to n^2 // cache the twoSum results, then full scan the other two arrays for (inti=0; i < nums1.length; i++) { for (intj=0; j < nums2.length; j++) { inttwoSum= nums1[i] + nums2[j]; if (sum12.containsKey (twoSum)) { sum12.put(twoSum, sum12.get(twoSum) + 1); }else { sum12.put(twoSum, 1); } } }
for (intk=0; k < nums3.length; k++) { for (intl=0; l < nums4.length; l++) { inttarget=0 - nums3[k] - nums4[l];
if (sum12.containsKey(target)) { ans += sum12.get(target); } } }
// result in duplicate answers, for instance, [-1, 0, 1, 2, -1, -4] // [-1, 0, 1] and [0, 1, -1], which is hard to check
// public List<List<Integer>> threeSum(int[] nums) { // List<List<Integer>> ans = new LinkedList<>();
// for (int i = 0; i < nums.length; i++) { // for (int j = i + 1; j < nums.length; j++) { // for (int k = j + 1; k < nums.length; k++) { // if (nums[i] + nums[j] + nums[k] == 0) { // List<Integer> res = new ArrayList<>( // Arrays.asList(nums[i], nums[j], nums[k])); // ans.add(res); // } // } // } // } // return ans; // }
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans = newLinkedList<>(); Arrays.sort(nums);
// if the smallest element in the sorted array is larger than 0 // there is no valid element groups if (nums[0] > 0) { return ans; }
for (inti=0; i < nums.length; i++) { // if the same element has been checked before // then its corresponding left and right must // be same, thus let's just skip them if (i != 0 && nums[i] == nums[i - 1] ) { continue; }
// for any fixed nums[i], use two pointer scanning the array // and the three sum problem is converted to finding two sum // which is equals to -nums[i] intleft= i + 1; intright= nums.length - 1;
while (left < right) { intsum= nums[i] + nums[left] + nums[right]; if( sum == 0) { ans.add (newLinkedList<>( Arrays.asList(nums[i], nums[left], nums[right]))); while (left < right && nums[left] == nums[left + 1]) { left++; }
while (left < right && nums[right] == nums[right - 1]) { right--; } left++; right--; }elseif ( sum > 0) { right--; }else { left++; } }
}
return ans; } }
这道题的核心难度在于去重,也就是说我们不希望有(a,b,c)这样的三元数组后,再有(b,a,c) 或者(c,a,b, 因此,在循环中我们希望始终保持循环下标间的顺序为 i < j < k.
classSolution { public List<List<Integer>> fourSum(int[] nums, int target) { List<List<Integer>> ans = newLinkedList<>();
Arrays.sort(nums);
if ( nums.length < 4) { return ans; }
for (inti=0; i < nums.length; i++) {
// if nums[i] is larger than target and not negative // no need checking the left number if (nums[i] > target && nums[i] >= 0){ break; } if (i > 0 && nums[i] == nums[i - 1]){ continue; } for (intj= i + 1; j < nums.length; j++) { if (nums[i] + nums[j] > target && nums[i] >= 0) { break; } // if and only if j > i + 1 && nums[j] == left element // should we skip it, as there may be a group [2,2,2,2] if (j > i + 1 && nums[j] == nums[j - 1]) { continue; }