LeetCode 18.四数之和 剪枝+排序+双指针 C/C++

题目链接
主要类比三数之和,在此基础之上进行操作。

主要思路:三数之和是在确定第一个数字之后,采用双指针确定剩余两个数字,同样的,四数之和我们在确定第一个和第二个数字的基础上,再采用双指针确定剩余两个数字,从而使时间复杂度降为 O ( n 3 ) O(n^3) O(n3)
剪枝:本题要剪枝一下,因为样例中四数之和会超出int范围,过不了。①确定第一个数字之后,如果 n u m s [ i ] + n u m s [ i + 1 ] + n u m s [ i + 2 ] + n u m s [ i + 3 ] > t a r g e t nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target,即 n u m s [ i ] nums[i] nums[i]和后面连续的三个数字之和已经大于target了,那么此数组中就不存在等于target的四元组,直接break。②确定第一个数字之后,如果 n u m s [ i ] + n u m s [ n − 1 ] + n u m s [ n − 2 ] + n u m s [ n − 3 ] < t a r g e t nums[i]+nums[n-1]+nums[n-2]+nums[n-3]<target nums[i]+nums[n1]+nums[n2]+nums[n3]<target,即针对 n u m s [ i ] nums[i] nums[i]和最后三个数字之和如果小于target,说明针对此nums[i]就没有符合条件的四元组等于target了,因为最大的都小于target了,那么就跳过continue,遍历下一个 n u m s [ i ] nums[i] nums[i]了。然后确定第二个数字之后,同样的方法剪枝。
其他细节详见代码。

class Solution {
public:
	vector<vector<int>> fourSum(vector<int>& nums, int target) {
		vector<vector<int>> ans;
		if(nums.size()<4)return ans;

		sort(nums.begin(),nums.end());
		int n = nums.size();
		for(int i = 0;i<n-3;i++) {//确定第一个元素
			if(i>0&&nums[i]==nums[i-1])continue;
			//确定第一个元素后剪枝
			if((long long)nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target) break;//即最小的数都大于target了,那就没必要继续了
			//最大的数比target小也没必要继续了,注意这里所说的大小是针对nums[i]已经确定的情况
			//所以是continue,不同于上面的break,因为随着第一个数字的增大,可能出现等于target的情况
			if((long long)nums[i]+nums[n-1]+nums[n-2]+nums[n-3]<target) continue;

			for(int j = i+1;j<n-2;j++) {//确定第二个元素
				if(j>i+1&&nums[j]==nums[j-1])continue;
				//确定第二个元素后剪枝
				if((long long)nums[i]+nums[j]+nums[j+1]+nums[j+2]>target)break;
				if((long long)nums[i]+nums[j]+nums[n-1]+nums[n-2]<target)continue;
				int left = j+1;
				int right = n-1;
				while(left<right){
					int quard = nums[i]+nums[j]+nums[left]+nums[right];
					if(quard==target){
						ans.push_back({nums[i],nums[j],nums[left],nums[right]});
						//去重
						while(left<right&&nums[left+1]==nums[left])left++;
						left++;//还需要加1的原因是刚才移到了最后一个重复的数字,下一个才是要遍历的
						while(left<right&&nums[right-1]==nums[right])right--;
						right--;

					}
					else if(quard<target) {
						left++;
					}
					else {
						right--;
					}
				}
			}
		}
		return ans;
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值