描述
给定一个n个整数的数组S,在S中找到三个整数,使得总和最接近给定数量的目标。返回三个整数的和。你可以假设每个输入都只有一个解决方案。
例如,给定数组S = {-1 2 1 -4},target = 1。 最接近目标的总和是2.(-1 + 2 + 1 = 2)。
解决方案
和上次做的三个数和为0那个题很像,所以首先要想到的当然就是给这个无序数组排序,这样能降低之后的匹配过程的复杂度。
我又一次本着先做对后看事件复杂度的态度,先按照最传统的方法做出来了,惊喜的是,通过了,虽然时间复杂度还是很高,下面是我写的方法:
public int threeSumClosest(int[] nums, int target) { Arrays.sort(nums); int distance = Math.abs(target-(nums[0]+nums[1]+nums[2])); int sum = nums[0]+nums[1]+nums[2]; for(int i=0; i<nums.length-2;i++){ if(i == 0 || (i > 0 && nums[i] != nums[i-1])){ for(int j=i+1; j<nums.length-1; j++){ if(j == (i+1) || (j > (i+1) && nums[j] != nums[j-1])){ for(int n=j+1; n<nums.length; n++){ if((n == (j+1) || (n > (j+1) && nums[n] != nums[n-1])) && (distance>Math.abs(target-(nums[i]+nums[j]+nums[n])))){ distance = Math.abs(target-(nums[i]+nums[j]+nums[n])); sum = nums[i]+nums[j]+nums[n]; } } } } } } return sum; }
然后看了讨论区中大神们做的,很厉害,其方法还是利用之前那个从两边趋近中间的方法,思想如下:
1、先定义第一个数的位置,然后再以第一个数右边一位的数为最左数,以最后一位数为最右数。
2、把第一个数,最左数和最右数这三个数加和。
3、如果此时三个数的和大于目标数,那么说明最右数过大,那么最右数向左移动一位。重复步骤2。
4、如果三个数和小于目标数,那么说明最左数过小,那么最左数右移动一位。重复步骤2。
5、在进行2/3/4步骤同时,比较最短距离和记录三个数的和,以便最后得到正确结果并返回。
具体代码如下:
public int threeSumClosest1(int[] num, int target) { int result = num[0] + num[1] + num[num.length - 1]; Arrays.sort(num); for (int i = 0; i < num.length - 2; i++) { int start = i + 1, end = num.length - 1; while (start < end) { int sum = num[i] + num[start] + num[end]; //如果此时三个数和大于target,说明最大数过大(即num[end]过大),那么就要减小大数,否则增大小的数(即num[start]过小) if (sum > target) { end--; } else { start++; } if (Math.abs(sum - target) < Math.abs(result - target)) { result = sum; } } } return result; }