【leetcode】16. 最接近的三数之和(回溯超时,两个指针优化)

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

示例:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

提示:

3 <= nums.length <= 10^3
-10^3 <= nums[i] <= 10^3
-10^4 <= target <= 10^4

看上去跟回溯很类似,但是超时了,因为回溯的时间复杂度是o(N!)


void updateSum(const vector<int>& res, const int target, int& sum)
{
	int res_sum = 0;
	for (int i = 0; i < 3; i++)
	{
		res_sum += res[i];
	}
	if (abs(res_sum - target) < abs(sum - target))
	{
		sum = res_sum;
	}
}

void threeSumClosestImpl(const vector<int>& nums, vector<int>& res, int& sum, const int target, vector<int>& used)
{
	if (res.size() == 3)
	{
		updateSum(res, target, sum);
		return;
	}
	for (int i = 0; i < nums.size(); i++)
	{
		if (used[i] == 0)
		{
			res.push_back(nums[i]);
			used[i] = 1;
			threeSumClosestImpl(nums, res, sum, target, used);

			res.pop_back();
			used[i] = 0;
		}
	}
}

// https://leetcode-cn.com/problems/3sum-closest/
//16. 最接近的三数之和。 按照全排列的方式去解决,N!肯定要超时
int threeSumClosest(vector<int>& nums, int target) {
	vector<int> res;
	int sum = 999999;
	vector<int> used(nums.size() + 1, 0);

	threeSumClosestImpl(nums, res, sum, target, used);

	return sum;
}

暴力枚举,虽然通过了,但是效率太低,垫底

int threeSumClosest(vector<int>& nums, int target) {
	int curSum = nums[0] + nums[1] + nums[2];

	std::sort(nums.begin(), nums.end());

	for (int i = 0; i < nums.size(); i++)
	{
		for (int j = i + 1; j < nums.size(); j++)
		{
			for (int k = j + 1; k < nums.size(); k++)
			{
				if (abs(curSum - target) > abs((nums[i] + nums[j] + nums[k]) - target))
				{
					curSum = nums[i] + nums[j] + nums[k];
				}
			}
		}
	}
	return curSum;
}

正常的解法:
可以参考 三个数的和(https://leetcode-cn.com/problems/3sum/) 那道题目。

先将数组排序。
先固定一个数i,剩下两个数分别为leftright,初始时left指向i+1,right指向数组的最后一个元素。

t = nums[i] + nums[left] + nums[right]

当t > target时,right左移,当t < target时,left右移,两个指针最后逼夹,最后会找到一个

t - nums[i] = nums[left] + nums[right]

的一个最接近的值,( t - nums[i] )在此层循环里是个定值。

所以两层循环,时间复杂度O(n2)平方

// 排序后,使用两个指针来找
int threeSumClosest3(vector<int>& nums, int target) {
	
	std::sort(nums.begin(), nums.end());
	int curSum = nums[0] + nums[1] + nums[2];
	int left, right;

	for (int i = 0; i < nums.size()-2; i++) // 最后两个数要留出来余量,left和right和i不应该相同
	{
		left = i + 1;
		right = nums.size() - 1;
		while (left < right)
		{
			int t = nums[left] + nums[right] + nums[i];
			if (abs(curSum - target) > abs(t - target))
			{
				curSum = t;
			}
			if (t > target)
			{
				right--;
			}
			if (t < target )
			{
				left++;
			}
			if (t == target) // 防止死循环
			{
				return t;
			}
		}
	}
	return curSum;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值