这里是题目描述:LeetCode-16.最接近的三数之和
本题的直观做法是:列举出所给的数组nums
中所有的的三数组合,寻找出所有三数之和中与target
最接近的。这种方法需要对数组nums
进行三层遍历,时间复杂度 O(n3) 。接下来我们使用一种基于双指针的解法,时间复杂度被简化为 O(n2)
双指针解法
第一步,对数组nums
进行升序排序。这里我们要引入一个经验之谈:对于许多题干中给出一个数组的问题,如果没有要求不能破坏原数组的顺序结构,那么我们可以尝试对数组进行排序,也许可以基于排序后的数组得到时间或空间效率更优的解法
对于数组中的任意三个数字,一定有左边的数字,中间的数字和右边的数字,依次尝试将中间的数字固定为nums[1]、nums[2]、...nums[n-2]
,每次将左右两边的数字初始化为中间数字左边第一个数字和右边第一个数字,如图:
当此时的三数之和sum
大于target
时,我们希望减小sum
以达到更接近target
的目的,于是我们将指向左边数字的指针left
左移一位;如果sum
小于target
时,我们希望增大sum
以达到更接近target
的目的,于是我们将指向右边数字的指针right
右移一位;在此过程中记录并更新最接近target
的sum
,直到left
无法再左移或right
无法再右移;便尝试下一个中间数字。特别地,如果有遇到sum==target
,便可直接将sum
返回为结果
题解代码:
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int nearest=nums[0]+nums[1]+nums[2];
for(int i=1;i<nums.length-1;i++)
{
int p1=i-1,p2=i+1;
while(p1>=0 && p2<nums.length)
{
int sum=nums[i]+nums[p1]+nums[p2];
if(sum==target)
{
return target;
}
if(Math.abs(target-sum)<Math.abs(target-nearest))
{
nearest=sum;
}
if(sum>target)
{
p1-=1;
}
else
{
p2+=1;
}
}
}
return nearest;
}
}
时间复杂度:排序需要O(nlogn),双指针寻找最接近的三数和需要尝试O(n)的中间数,每个中间数需要尝试O(n)的左右数字,因此总时间复杂度为O(n2)
空间复杂度:O(1)