Leetcode刷题知——16.最接近的三数之和【排序+三指针】
前言
最近加入了leetcode的刷题计划,每日5题,不过有时候还是交了之前写过的题目。
今天写了这道题目,第16题,16. 最接近的三数之和 - 力扣(LeetCode) (leetcode-cn.com)
感兴趣的小伙伴可以去挑战一下,很简单。
题目
描述
给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。
示例
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
输入:nums = [0,0,0], target = 1
输出:0
提示
3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-104 <= target <= 104
解题思路【排序 + 三指针】
这题我其实一开始是想到排序 + 滑动窗口的思路的,先排序,然后窗口滑动,但是发现了,这样子会错失一些数值,导致WA声一片。
但是如果使用最暴力的三重循环枚举无疑太笨了,我们应该使用复杂度较低的方法实现。
我们其实可以用三指针去解决,先按顺序排序,然后枚举出三数中的最小值,然后在后面的边界去枚举剩下的两个值,对这两个值的枚举,我们可以做一些优化,比如初始化为剩余的最小和最大,然后我们计算三数和,如果小于目标值则移动较小的那一个,如果大于,则移动较大的那一个,然后动态更新答案。
小细节
当枚举出相等时可以直接返回。
Code(C++)
#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
class Solution
{
public:
/// <summary>
/// 排序 + 三指针
/// 先排序
/// 然后使用第一个指针 枚举出三数的最小元素
/// 然后使用使用两个指针,初始指向后面的左右边界
/// 根据三数和 与 target的大小关系 进行移动
/// 如果相等直接返回
/// </summary>
/// <param name="nums"></param>
/// <param name="target"></param>
/// <returns></returns>
int threeSumClosest(vector<int>& nums, int target)
{
// 排序
sort(nums.begin(), nums.end());
int n = nums.size();
// 三数
int a, b, c;
// 初始化一下答案
int ans = nums[0] + nums[1] + nums[2];
// 第一个指针
for (int i = 0; i < n; ++i)
{
a = nums[i];
// 枚举后面两个指针
for (int j = i + 1, k = n - 1; j < k;)
{
b = nums[j], c = nums[k];
// 相等时直接返回
if (a + b + c == target)
{
return target;
}
// 否则动态更新答案
int sum = a + b + c;
ans = (abs(target - sum) < abs(target - ans)) ? sum : ans;
// 根据数值移动指针
// 小于目标值,移动b的指针
if (sum < target)
{
j++;
}
// 大于则移动 c的指针
else
{
k--;
}
}
}
// 返回答案
return ans;
}
};
int main(int argc, char** argv)
{
int n;
cin >> n;
vector<int> nums(n);
for (int& num : nums)
{
cin >> num;
}
int target;
cin >> target;
Solution sol;
cout << sol.threeSumClosest(nums, target) << endl;
return 0;
}
后话
又是充实的一天,真不错。