描述
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
来源:力扣(LeetCode)
链接:16. 3Sum Closest
解题思路
这里介绍两种解法, 第一种就是暴力解法, 因为是3个数相加, 需要循环三遍, 时间复杂度为O(N3).
首先, 将与target最接近的三个数的和初始化为closest = nums[0] + nums[1] + nums[2], 将两者之差记为diff = abs(target - closest). 然后遍历所有可能的sum = nums[i] + nums[j] + nums[k], 如果有sum与target更加接近, 则基于sum更新diff和cloesst. 具体代码看解法一.
第二种解法主要分成两步, 第一步先进行排序, 然后对排好序的数组运用头尾双指针法. 快排的时间复杂度为O(NlgN), 头尾双指针法的时间复杂度为O(N2), 总体的时间复杂度为O(N2).
同样要定义一个变量 diff 用来记录差的绝对值,然后开始遍历数组,先是确定一个数,然后用两个指针 left 和 right 来滑动寻找另外两个数,将三数之和记为sum = nums[i] + nums[left] + nums[right],如果有sum与target更加接近, 则基于sum更新diff和closest,如果sum > target, 则right++, 否则left++, 具体代码见解法二.
代码
解法一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| int threeSumClosest(int* nums, int numsSize, int target) { int i, j, k; int closest = nums[0] + nums[1] + nums[2]; int diff = abs(closest - target); for(int i = 0; i < numsSize; i++) for(int j = i + 1; j < numsSize; j++) for(int k = j + 1; k < numsSize; k++) { int sum = nums[i] + nums[j] + nums[k]; int newDiff = abs(sum - target); if(newDiff < diff) { diff = newDiff; closest = sum; } } return closest; }
|
解法二
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
|
#include <stdlib.h>
int compare(const void *a, const void *b) { return (*(int*)a - *(int*)b); }
int threeSumClosest(int* nums, int numsSize, int target) { int closest = nums[0] + nums[1] + nums[2]; int diff = abs(closest - target); qsort(nums, numsSize, sizeof(int), compare); for (int i = 0; i < numsSize - 2; ++i) { int left = i + 1, right = numsSize - 1; while (left < right) { int sum = nums[i] + nums[left] + nums[right]; int newDiff = abs(sum - target); if (diff > newDiff) { diff = newDiff; closest = sum; } if (sum < target) ++left; else --right; } } return closest; }
|