题目:能否快速找出一个数组中的两个数字,让这两个数字之和等于一个给定的值,为了简化起见,我们假设这个数组中肯定存在至少一组符合要求的解。
例如有如下两个数组:5,6,1,4,7,9,8,给定sum = 10,则这两个数为1和9
思路一:就是枚举,从数组中任意取出两个数字,计算两者之和为给定的数字。其复杂度为O(n^2),这种方法很容易,就是效率不高。
思路二:先排序,对于a[i],则可以查找sum - a[i],看数组中有没有这个数,查找方法可以用二分或者哈希,这种方法可以将复杂度降低到O(nlogn)
思路三:先排序,然后通过两个下标的遍历来得出结果,附代码如下:
扩展问题:
1. 如果把这个问题中的"两个数字"改成"三个数字",解答时什么?
2. 如果完全相等的一对数字找不到,能否找到和最接近的解?
解:其实这两题跟leetcode的题目有点类似,我把leetcode上的2sum,3 sum,3 sum closest,4 sum这几题目可以拿来跟这个题目一起讨论
#include <iostream>
#include <algorithm>
#include <vector>
#include <stdlib.h>
using namespace std;
int main()
{
vector<int> arr;
int n;
cin >> n;
int temp;
for(int i = 0;i !=n; i++)
{
cin >> temp;
arr.push_back(temp);
}
sort(arr.begin(),arr.end());
int sum;
cin >> sum;
int closet;
int i = 0, j = arr.size() - 1;
while(i < j)
{
if(arr[i] + arr[j] > sum)
j--;
else if(arr[i] + arr[j] < sum)
i++;
else
{
cout << arr[i] << " " << arr[j] << endl;
i++;
j--;
}
}
system("pause");
}
Given an array of integers, find two numbers such that they add up to a specific target number.
The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.
You may assume that each input would have exactly one solution.
Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2
#include <iostream>
#include <algorithm>
#include <vector>
#include <stdlib.h>
using namespace std;
struct pai{
int data;
int idx;
bool operator< (const pai& rhs) const{
return data < rhs.data;
}
};
vector<int> twoSum(vector<int>& numbers, int target)
{
vector<int> res;
vector<pai> seq(numbers.size()) ;
for(int i = 0; i < numbers.size(); i++)
{
seq[i].data = numbers[i];
seq[i].idx = i;
}
sort(seq.begin(), seq.end());
int i = 0;
int j = seq.size() - 1;
while(i < j)
{
int plus = seq[i].data + seq[j].data;
if(plus == target)
{
int minIndex = min(seq[i].idx, seq[j].idx);
int maxIndex = max(seq[i].idx, seq[j].idx);
res.push_back(minIndex);
res.push_back(maxIndex);
i++;
}
else if(plus < target)
{
i++;
}
else
{
j--;
}
}
return res;
}
int main()
{
vector<int> num;
for(int i = 0;i < 11; i++)
num.push_back(i);
vector<int> result = twoSum(num, 10);
for(int i = 0; i <result.size(); i++)
{
cout << result[i] << " ";
if((i + 1)%2 == 0)
cout << endl;
}
system("pause");
}
3 sum
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
- Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ? b ? c)
- The solution set must not contain duplicate triplets.
For example, given array S = {-1 0 1 2 -1 -4}, A solution set is: (-1, 0, 1) (-1, -1, 2)
//利用set来把重复的给消除掉
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <iostream>
#include <set>
using namespace std;
vector<vector<int> > threeSum(vector<int> &num) {
vector<vector<int> > res;
sort(num.begin(), num.end());
for(int k = num.size() -1; k >= 0; k--)
{
int i = 0;
int j = k - 1;
if(i == k) i++;
if(j == k) j--;
vector<int> result;
int subsum = - num[k];
while(i < j)
{
int plus = num[i] + num[j];
if(plus == subsum)
{
result.push_back(num[i]);
result.push_back(num[j]);
result.push_back(num[k]);
res.push_back(result);
result.clear();
i++,j--;
}
else if(plus < subsum)
{
i++;
}
else
{
j--;
}
if(i == k) i++;
if(j == k) j--;
}
}
set<vector<int> > demo;
for(int i = 0;i != res.size(); i++)
demo.insert(res[i]);
vector<vector<int> > temp;
for(set<vector<int> >::iterator iter = demo.begin(); iter != demo.end(); iter++)
temp.push_back(*iter);
return temp;
}
int main()
{
int a[] = {0,0,0,-1,-2,2,1,-3,-3,3,-1};
vector<int> num;
for(int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
num.push_back(a[i]);
vector<vector<int> >results = threeSum(num);
for(vector<vector<int> >::iterator iter = results.begin(); iter != results.end(); ++iter)
{
for(int j = 0; j < 3; ++j)
{
cout << (*iter)[j] << " ";
}
cout << endl;
}
system("pause");
}
3 sum closest
Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.
For example, given array S = {-1 2 1 -4}, and target = 1. The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
#include <cmath>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <iostream>
#include <set>
using namespace std;
int threeSumClosest(vector<int> &num, int target) {
sort(num.begin(), num.end());
int ret;
bool first = true;
for(int k = num.size() - 1; k >= 0; k--)
{
int i = 0;
int j = k - 1;
while(i < j)
{
int sum = num[i] + num[j] + num[k];
if(first)
{
ret = sum;
first = false;
}
else
{
if(abs(sum - target) < abs(ret - target))
ret = sum;
}
if(ret == target)
return ret;
else if(sum < target)
i++;
else
j--;
}
}
return ret;
}
int main()
{
int a[] = {1,1,1,0};
vector<int> num;
for(int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
num.push_back(a[i]);
cout << threeSumClosest(num, 100) << endl;
system("pause");
}
4 sum
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Note:
- Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ? b ? c ? d)
- The solution set must not contain duplicate quadruplets.
For example, given array S = {1 0 -1 0 -2 2}, and target = 0. A solution set is: (-1, 0, 0, 1) (-2, -1, 1, 2) (-2, 0, 0, 2)
解:
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <iostream>
#include <set>
using namespace std;
vector<vector<int> > fourSum(vector<int> &num, int target) {
vector<vector<int> > res;
sort(num.begin(), num.end());
for(int t = num.size() - 1; t > 0; t--)
{
for(int k = t -1; k > 0; k--)
{
if(k==t) k--;
int i = 0;
int j = k - 1;
if(i == k) i++;
if(j == k) j--;
vector<int> result;
int subsum =target - num[k] - num[t];
while(i < j)
{
int plus = num[i] + num[j];
if(plus == subsum)
{
result.push_back(num[i]);
result.push_back(num[j]);
result.push_back(num[k]);
result.push_back(num[t]);
res.push_back(result);
result.clear();
i++,j--;
}
else if(plus < subsum)
{
i++;
}
else
{
j--;
}
if(i == k) i++;
if(j == k) j--;
}
}
}
set<vector<int> > demo;
for(int i = 0;i != res.size(); i++)
demo.insert(res[i]);
vector<vector<int> > temp;
for(set<vector<int> >::iterator iter = demo.begin(); iter != demo.end(); iter++)
temp.push_back(*iter);
return temp;
}
int main()
{
int a[] = {1, 0, -1, 0, -2, 2};
vector<int> num;
for(int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
num.push_back(a[i]);
vector<vector<int> >results = fourSum(num,1);
for(vector<vector<int> >::iterator iter = results.begin(); iter != results.end(); ++iter)
{
for(int j = 0; j < 4; ++j)
{
cout << (*iter)[j] << " ";
}
cout << endl;
}
system("pause");
}
思考问题:如果把3 sum closest 的三个数改成人一个数字呢?那会是什么情况?
思考问题:如果不用set,怎么去除掉vector< vector<int> >中重复的元素?
再思考:用递归去解决3 sum的问题?有什么特别的方法?参见:http://blog.csdn.net/kindlucy/article/details/8011299