1 sum of three numbers
I feel good after practicing with the sum of two algorithm mentioned above. I feel a little like doing a problem,
Today, when I saw the topic of the sum of three, I couldn't wait to do it
2 sum of three numbers
Give you an array of n integers, nums and target. Judge whether there are three elements a, b and c in nums, so that a + b + c = target? Please find all triples whose sum is target and does not duplicate.
Example:
Input: num = [5,12,6,3,9,2,1,7] target = 13 output: [[5,6,2], [5,1,7], [3,9,1]]
Train of thought 1
With the foreshadowing of the problem of the sum of two numbers mentioned above, I first thought of fixing a certain value, and then find the sum of two numbers as the residual value
For example, fix the first number 5, and then find two numbers in other numbers whose sum is 13-5 = 8
public static List<List<Integer>> threeSum(int[] nums, int target) { List<List<Integer>> result = new ArrayList<>(); for (int i = 0; i < nums.length; i++) { int need = target - nums[i]; //Sum of two processes Map<Integer, Integer> data = new HashMap<>(); for (int j = i + 1; j < nums.length; j++) { int d2 = need - nums[j]; if (data.containsKey(d2)) { result.add(Arrays.asList(nums[i], nums[j], d2)); } data.put(nums[j], j); } } return result; }
This method can complete this problem, but the complexity of the algorithm is O(n) ²), The spatial complexity is O(n) (used to construct the sum of two map multiple times)
At the same time, it is suspected of relying on the sum of two numbers
The disadvantage is that the space complexity is too large. Try to reduce the space complexity to O(1)
Train of thought 2
In fact, the sum of three numbers has lost the advantage of fast positioning with hash. If the solution in front of the hard board wastes space, you need to build the hash table many times
At this time, it is not necessary to stick to the previous solution
Using sorting + double pointer solution
public static List<List<Integer>> threeSum2(int[] nums, int target) { List<List<Integer>> result = new ArrayList<>(); Arrays.sort(nums); for (int i = 0; i < nums.length; i++) { int need = target - nums[i]; //Find the number whose sum of the remaining two numbers is need //Because it is an array that has been sorted, you can use the first and last two pointers to control the size of the sum for (int j = i + 1, k = nums.length - 1; j < nums.length; j++) { //If the sum of the two numbers is greater than need, it is possible to find the answer by moving the right pointer to the left, that is, moving k-- in the smaller direction //If the sum of the two numbers is less than need, the left pointer moves to the right, that is, towards the larger direction to move j++ while (j < k && nums[j] + nums[k] > need) { k--; } //End of traversal if (j == k) { break; } //Find answers that meet the conditions if (nums[j] + nums[k] == need) { result.add(Arrays.asList(nums[i], nums[j], nums[k])); } } } return result; }
- It seems to be a three-level cycle, but the movement times of pointers j and k in each round add up to n-1 times, so the overall time complexity of the solution is O (n) ²).
- Most importantly, the solution does not use additional sets (sorting is performed directly on the input array), so the spatial complexity is only O (1)
3 another sum of three numbers
Give you an array nums containing n integers. Judge whether there are three elements a, b and c in nums, so that a + b + c = 0? Please find all triples with a sum of 0 and no repetition.
Note: the answer cannot contain duplicate triples.
Example 1:
Input: nums = [-1,0,1,2,-1,-4] output: [[- 1, - 1,2], [- 1,0,1]] example 2:
Input: num = [] output: [] example 3:
Input: num = [0] output: []
thinking
This question can be regarded as a special version of the sum of three of the first question, that is, the version with target=0
It's actually the same idea to rewrite the while loop
public static List<List<Integer>> threeSums(int[] nums) { Arrays.sort(nums); List<List<Integer>> result = new ArrayList<>(); for (int i = 0; i < nums.length; i++) { if (i > 0 && nums[i] == nums[i - 1]) {//duplicate removal continue; } int start = i + 1, end = nums.length - 1; int need = -nums[i]; while (start < end) { int sum = nums[start] + nums[end]; if (sum > need) { end--; } else if (sum < need) { start++; } else { result.add(Arrays.asList(nums[i], nums[start], nums[end])); while (start < end && nums[start] == nums[start + 1]) {//duplicate removal start++; } while (start < end && nums[end] == nums[end - 1]) {//duplicate removal end--; } start++; end--; } } } return result; }
4 the sum of the nearest three numbers
Given an array of n integers, nums, and a target value, target. Find three integers in nums so that their sum is closest to target. Return the sum of these three numbers. Assume that there is only a unique answer for each set of inputs.
Example:
Input: num = [- 1,2,1, - 4], target = 1, output: 2 explanation: the closest sum to target is 2 (- 1 + 2 + 1 = 2).
thinking
After doing the sum of three problem, I see this problem. I still think of sorting + double pointer. Try to realize this idea
It took almost ten minutes to write, but it didn't pass. I still feel the train of thought is not smooth
public int threeSumClosest(int[] nums, int target) { Arrays.sort(nums); int result = nums[0] + nums[1] + nums[2]; for (int i = 0; i < nums.length; i++) { for (int j = i + 1, k = nums.length - 1; j < nums.length; j++) { int nextSum = nums[i] + nums[j] + nums[k]; while (j < k) { if (Math.abs((target - nextSum)) < Math.abs(target - result)) { result = nextSum; } if (target - nextSum > 0) { k--; } } } } return result; }
Look at Dapeng's solution. It's really beautiful. It's clear and logical
public int threeSumClosest(int[] nums, int target) { Arrays.sort(nums); //Initial sum int ans = nums[0] + nums[1] + nums[2]; for(int i=0;i<nums.length;i++) { //Double pointer int start = i+1, end = nums.length - 1; while(start < end) { int sum = nums[start] + nums[end] + nums[i]; if(Math.abs(target - sum) < Math.abs(target - ans)) ans = sum; //If it is greater than the target value, it needs to be moved to the left if(sum > target) end--; //If it is less than the target value, it needs to be shifted to the right else if(sum < target) start++; else return ans; } } return ans; }