问题描述
题目
给定一个目标值 target,请在整数数组 a中,找出三个元素(x,y,z) 使x+y+z==target。
请找到所有满足条件的三元组,并且请按从小到大的顺序输出所有合法的三元组。
注意:三元组中不允许包含重复数字,且输出的三元组中要求 x<y<z.
例如:给定target = 17,n=7, 数组a= [0, 2, 7, 10, 15,18,25]
结果返回两个三元组:(0,2, 15), (2,7,10)
输入
输入数据为2行,第一行有两个整数 target和n,其中target代表要搜索的目标和,n表示数组a的元素个数
第二行表示数组a的n个数,每个元素用空格隔开。
样例:
17 7
0 2 7 10 15 18 25
输出
输出所有满足和为target的三元组(x,y,z),要求(x< y <z) 并且不允许有重复数字。
把三元组按照x的大小升序输出,x相同的按照y的大小升序输出。
样例
0 2 15 0 7 10
思路
我们采取先定下第一个元素,再去寻找剩余两个元素的办法来查找这三个元素。首先,我们对数组进行升序排序,以保证寻找到的元素的顺序符合题意。
然后遍历数组,先把遍历到的元素定为三元组中的第一个元素。然后将左右两个指针分别指向这个元素的下一个元素以及数组的最后一个元素。判断这个三元组的和,如果三元组的和大于目标值,则需要减小和,也就是有指针需要向左移动,同理,如果三元组的和小于目标值,左指针需要向右移动。如果找到了一个三元组,则左右指针同时收缩,并且去重,查找下一组。
当左右指针相遇时,这一轮查找就结束了,把三元组的第一个元素向右移动,去重后开始下一组的查找。注意去重应该和前一个元素比,否则会漏掉前两个元素相同的情况。
代码实现
先实现寻找三元组的函数。
void threesum(vector<int> nums,int target){
sort(nums.begin(),nums.end());//先对数组进行升序排序
for(int i=0;i<nums.size();i++){
if(i>0&&nums[i]==nums[i-1]){//去重和前面一个元素相同时,不再判断
continue;
}
int left=i+1,right=nums.size()-1;//双指针起始位置
while(left<right){//双指针相遇时,循环结束
int sum=nums[i]+nums[left]+nums[right];
if(sum>target)//因为数组已经按升序排序,所以当和大于目标值时,需要右边的元素减小
right--;
else if(sum<target)//同理,和小于目标值时,需要左边的元素增大
left++;
else{
cout<<nums[i]<<" "<<nums[left]<<" "<<nums[right]<<endl;//找到一组和时输出
//向里去重,开始寻找下一组
left++;
right--;
while(left<right&&nums[left]==nums[left-1])
left++;
while(left<right&&nums[right]==nums[right+1])
right--;
}
}
}
}
在主函数中实现出输入的功能,问题解决。
int main(){
int target,n;
cin>>target>>n;
vector<int> nums;
for (int i=0;i<n;i++){
int tmp;
cin>>tmp;
nums.push_back(tmp);
}
threesum(nums, target);
}