一、题目描述
二、解题思路
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
* 找到最小的差值, 拆解成子问题,找到每一种情况的 min(target - (nums[i]+nums[j]+nums[k]))
* 再拆解,nums[i] + (nums[j]+nums[k])
* O(n^2)
* 还是想办法写出所有的情况,穷举出来,硬性可以三重循环,穷举所有情况,但是复杂度太高。
* 指明双指针, 那么就是需要抓小的现象和逻辑,来进行判断。
* 在之前的算面积的题中,为什么可以直接使用,双指针,其实跟顺序是有关系的,双指针能够生效的原因也是需要数组是有序的,不然根本不知道如何进行左移和右移。
*/
// var threeSumClosest = function(nums, target) {
// let min = Infinity;
// let res;
// let i = 0;
// let j = nums.length - 1;
// while (i < j) {
// for (let k = i + 1; k < j; k++) {
// const total = nums[i] + nums[j] + nums[k]
// if (Math.abs(target - total) < min) {
// res = total;
// min = Math.abs(target - total);
// // 第一次错误,封存,[-1,2,1,-4] 1, 这个解法丢了一种情况,丢失了所有的-1,2,1,覆盖不了所有情况
// }
// }
// i++
// }
// return res;
// };
// 当数组是有序的时候,这时候是不是就是可以固定一个数,然后双指针进行左右移动
// 错误:往
// var threeSumClosest = function(nums, target) {
// let sortNums = nums.sort((a, b) => a - b);
// let diff = Infinity;
// let val = null
// for (let i = 0; i < sortNums.length - 2; i++) {
// let l = i + 1;
// let r = sortNums.length-1;
// while (l < r) {
// const total = sortNums[i] + sortNums[l] + sortNums[r];
// if (Math.abs(target - total) < diff) { // 关键点,第一次采用的 Math.abs(),漏掉负数的情况[1,1,-1,-1,3],-1,错误输出成了 1
// diff = target - total;
// val = total;
// l++;
// } else {
// r--;
// }
// }
// }
// return val;
// }
var threeSumClosest = function(nums, target) {
nums.sort((a, b) => a - b);
let res = nums[0] + nums[1] + nums[nums.length - 1];
for (let i = 0; i < nums.length - 2; i++) {
let l = i + 1;
let r = nums.length-1;
while (l < r) {
const sum = nums[i] + nums[l] + nums[r];
// 看了题解,这边把移动指针和值拆分掉,会清晰很多
if (sum > target ) {
r--
} else {
l++
}
if (Math.abs(target - sum) < Math.abs(target - res)) {
res = sum
}
}
}
return res;
}
三、总结
总结:双指针基础是数组需要是有序的,或者是数组的位置是有关系的,才能生效。所以无序需要先排序。自己犯的几个错误:
- sort 是对原数组进行排序;
- 指针移动的时候最好跟逻辑拆分开来,这样便于我们进行逻辑书写;
- 移动指针的逻辑一定要想清楚,最开始写错了这边的逻辑。
if (sum < target ) { r--}