题意:3Sum题变种,给出n个数nums[]和一个target,求n中的3个数的组合使得其和与target相差值最小。
思路:传统的3Sum做法(LeetCode15),枚举三个数中的两个,然后求证剩余的数字是否在给出的集合中。后面一步可以时间换空间,用二分来做,这样复杂度乘上一个logn;也可以空间换时间,用数组直接存储或者hash挂链。
对于这一题,可以继续用传统的解法,先枚举三个数中的两个,但注意到目标答案的变化并不是单调的,即取出两个数nums[i]和nums[j]后,最优解的计算过程为ans=f(v)=min(target-nums[i]-nums[j]-v),这个关于v的函数是先减后增的,是一个经典的可以使用三分法计算最优解的模型。
很久没有写三分了,可能别人有更好的写法,这里介绍一种常数可能高一点但一定不会错的写法:
- 首先取l,r,得到端点间距离d=r-l;
- 如果d<3,退出循环,将l到r的每个点对应的值直接算出来从而对答案进行维护;
- 否则机算三等分的长度len=d/3,取p1=l+len,p2=r-len;
- 因为len=d/3<=(double)d/3,再加上之前d>=3时的约束,可以保证p1<p2;
- 比较f(p1)与f(p2)的大小,取较高者进行三分;
关于第5步取较高点的原因,下图即为例子: