陣列系列
力扣資料結構之陣列-00-概覽
力扣.53 最大子陣列和 maximum-subarray
力扣.128 最長連續序列 longest-consecutive-sequence
力扣.1 兩數之和 N 種解法 two-sum
力扣.167 兩數之和 II two-sum-ii
力扣.170 兩數之和 III two-sum-iii
力扣.653 兩數之和 IV two-sum-IV
力扣.015 三數之和 three-sum
力扣.016 最接近的三數之和 three-sum-closest
力扣.259 較小的三數之和 three-sum-smaller
題目
給你一個長度為 n 的整數陣列 nums 和 一個目標值 target。請你從 nums 中選出三個整數,使它們的和與 target 最接近。
返回這三個數的和。
假定每組輸入只存在恰好一個解。
示例 1:
輸入:nums = [-1,2,1,-4], target = 1
輸出:2
解釋:與 target 最接近的和是 2 (-1 + 2 + 1 = 2)。
示例 2:
輸入:nums = [0,0,0], target = 1
輸出:0
解釋:與 target 最接近的和是 0(0 + 0 + 0 = 0)。
提示:
3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-10^4 <= target <= 10^4
前言
這道題作為 leetcode 的第 15 道題,看起來似曾相識。
大概思路可以有下面幾種:
-
暴力解法
-
陣列排序+二分
-
Hash 最佳化
-
雙指標
v1-暴力解法
思路
直接 3 次迴圈,找到符合結果的資料返回。
這種最容易想到,一般工作中也是我們用到最多的。
大機率會超時。
實現
public int threeSumClosest(int[] nums, int target) {
final int n = nums.length;
int result = Integer.MAX_VALUE;
int minDis = Integer.MAX_VALUE;
for(int i = 0; i < n; i++) {
for(int j = i+1; j < n; j++) {
for(int k = j+1; k < n; k++) {
int sum = nums[i]+nums[j]+nums[k];
int dis = Math.abs(sum - target);
if(minDis > dis) {
minDis = dis;
result = sum;
}
}
}
}
return result;
}
效果
574ms 8.04%
竟然透過了,還挺意外的
小結
這裡慢在三層迴圈,可以考慮排序後利用雙指標最佳化。
可以參考 T015 的思路。
v2-排序+雙指標
思路
首先排序
固定第一個元素,然後後面兩個元素透過雙指標尋找,類似於 T015
這裡需要用一個變數記錄最小的距離,另一個記錄 result 和。
實現
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
// 處理雙指標
final int n = nums.length;
int result = Integer.MAX_VALUE;
int minDis = Integer.MAX_VALUE;
for(int i = 0; i < n-2; i++) {
int left = i+1;
int right = n;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
// 判斷是否為最小距離
if(sum == target) {
return target;
}
// 更新最小距離
int abs = Math.abs(sum - target);
if(abs < minDis) {
minDis = abs;
// 最小的 sum
result = sum;
}
if(sum > target) {
right--;
}
if(sum < target) {
left++;
}
}
}
return result;
}
效果
12ms 77.79%
效果還行。看了下基本實現就是這個。
小結
這裡對雙指標的理解要求比較高。
在理解了 T015 的基礎上實現這一題並不算特別難。