4Sum
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)思路和3Sum问题基本相同。
/** 整理的提交代码
* 处理复杂度为O(n4),其中的去重效率也不是很高
* 主要思路:(穷举所有,最后使用标准程序库中的算法进行去重)
* 1、为了选出的四元组是非递减的,先对输入数组进行排序
* 2、穷举法选取符合条件的四元组,由于每个元素只能取一次,所以当前循环的起始为上次循环起始之后
* 3、由于原始输入数组本身可能包含重复元素,所以需要对选取到的四元组进行筛选移除重复四元组
* 提交结果:
* (Judge Small)
* Run Status: Accepted!
* Program Runtime: 4 milli secs (基本在几毫秒)
* Progress: 15/15 test cases passed.
* (Judge Large)
* Run Status: Time Limit Exceeded (超时)
*/
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
class Solution {
public:
vector<vector<int> > fourSum(vector<int> &num, int target) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
sort(num.begin(), num.end());
size_t size = num.size();
vector<int> quadruplet;
vector<vector<int> > result;
for (size_t i = 0; i < size; i++)
{
for (size_t j = i+1; j < size; j++)
{
for (size_t k = j+1; k < size; k++)
{
for (size_t t = k+1; t < size; t++)
{
if (num[i] + num[j] + num[k] + num[t] == target)
{
quadruplet.push_back(num[i]);
quadruplet.push_back(num[j]);
quadruplet.push_back(num[k]);
quadruplet.push_back(num[t]);
result.push_back(quadruplet);
quadruplet.clear();
}
}
}
}
}
vector<vector<int> >::iterator end = result.end();
sort(result.begin(), result.end(), less<<vector<int> >()); // 此处必须排序,排序元素为四元祖
vector<vector<int> >::iterator new_end = unique(result.begin(), end);
result.erase(new_end, end);
return result;
}
};
int main()
{
int target;
cout << "input target: ";
cin >> target;
vector<int> num;
int number;
cout << "input an integer array: ";
while (cin >> number)
{
num.push_back(number);
}
vector<vector<int> > result;
Solution s;
result = s.fourSum(num, target);
for (size_t i = 0; i < result.size(); i++)
{
for (size_t j = 0; j < 4; j++)
{
cout << result[i][j] << ' ';
}
cout << endl;
}
return 0;
}
/** 整理的提交代码
* 处理复杂度为O(n3),其中的去重效率有所很高,“实时”去重
* 主要思路:(穷举第一个和第二个元素,对第三个和第四个元素使用首尾逼近来枚举)
* 具体思路和求3Sum的O(n2)方法相同
* 提交结果:
* (Judge Small)
* Run Status: Accepted!
* Program Runtime: 4 milli secs (基本在几毫秒)
* Progress: 15/15 test cases passed.
* (Judge Large)
* Run Status: Accepted!
* Program Runtime: 1420 milli secs (基本稳定在一点四毫秒左右)
* Progress: 282/282 test cases passed.
*/
#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;
class Solution {
public:
vector<vector<int> > fourSum(vector<int> &num, int target) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
vector<int> quadruplet;
vector<vector<int> > result;
sort(num.begin(), num.end());
size_t size = num.size();
if (size < 4)
{
return result;
}
int sum = 0;
// 下标ijkt为四元组各元素的下标
size_t i = 0, j = i+1, k = j+1, t = size-1;
for (i = 0; i < size-3; i++)
{
if (i > 0 && num[i] == num[i-1])
{
continue;
}
for (j = i+1; j < size-2; j++)
{
if (j > i+1 && num[j] == num[j-1])
{
continue;
}
k = j + 1;
t = size - 1;
while (k < t)
{
if (k > j+1 && num[k] == num[k-1])
{
k = k + 1;
continue;
}
sum = num[i] + num[j] + num[k] + num[t];
if (sum == target)
{
quadruplet.push_back(num[i]);
quadruplet.push_back(num[j]);
quadruplet.push_back(num[k]);
quadruplet.push_back(num[t]);
result.push_back(quadruplet);
quadruplet.clear();
k = k + 1;
if (num[k] == num[k-1])
{
k = k + 1;
}
}
else if (sum < target)
{
k = k + 1;
if (num[k] == num[k-1])
{
k = k + 1;
}
}
else
{
t = t -1;
if (num[t] == num[t+1])
{
t = t - 1;
}
}
}
}
}
return result;
}
};
/** 整理的提交代码
* 处理复杂度为O(n3),其中的去重效率有所很高,使用数据结构记录符合条件的元祖,查找去重
* 主要思路:(穷举第一个和第二个元素,对第三个和第四个元素使用首尾逼近来枚举)
* 具体思路和求3Sum的O(n2)方法相同,只是去重方法不同
* 为了避免直接查找string,对符合条件的元组进行了哈希,将这个元组的哈希函数返回值放入某个数据结构来标记该
* 符合条件的元组已经找出了,下次哈希到相同的结果认为它们原来的元组相同(假设哈希未出现冲突),则跳过保存该结果。
* 为了在求得符合条件的四元组后查找其哈希值时,提高查找速度,使用set或map来存储哈希值,其中的哈希值有序排列
* 调用这两种容器自身的查找函数可以提高查找效率(内部一般使用二分查找法)。
* 这里使用map和set在提交结果的时间上有所差别,应该二者内部实现还是有些差别,虽然可以将set也看做一种特殊map。
* 提交结果:
* (Judge Small)
* Run Status: Accepted!
* Program Runtime: 8 milli secs (基本在几毫秒)(使用map去重约为0毫秒)
* Progress: 15/15 test cases passed.
* (Judge Large)
* Run Status: Accepted!
* Program Runtime: 948 milli secs (基本稳定在九百多毫秒) (使用map去重约为600多毫秒)
* Progress: 282/282 test cases passed.
*/
#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
using namespace std;
class Solution {
public:
long RSHash(string str)
{
int a = 876283;
int b = 21382;
long hash = 0;
for(size_t i = 0; i < str.size(); i++)
{
hash = a * hash + str[i];
a = a * b;
}
return hash;
}
vector<vector<int> > fourSum(vector<int> &num, int target) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
vector<int> quadruplet;
vector<vector<int> > result;
sort(num.begin(), num.end());
size_t size = num.size();
if (size < 4)
{
return result;
}
string str;
set<long> lSet;
long hash;
int sum = 0;
// 下标ijkt为四元组各元素的下标
size_t i = 0, j = i+1, k = j+1, t = size-1;
for (i = 0; i < size-3; i++)
{
/*if (i > 0 && num[i] == num[i-1])
{
continue;
}*/
for (j = i+1; j < size-2; j++)
{
/*if (j > i+1 && num[j] == num[j-1])
{
continue;
}*/
k = j + 1;
t = size - 1;
while (k < t)
{
/*if (k > j+1 && num[k] == num[k-1])
{
k = k + 1;
continue;
}*/
sum = num[i] + num[j] + num[k] + num[t];
if (sum == target)
{
str.clear();
str += num[i];
str += num[j];
str += num[k];
str += num[t];
hash = RSHash(str);
if (lSet.find(hash) == lSet.end())
{
lSet.insert(hash);
quadruplet.push_back(num[i]);
quadruplet.push_back(num[j]);
quadruplet.push_back(num[k]);
quadruplet.push_back(num[t]);
result.push_back(quadruplet);
quadruplet.clear();
}
k = k + 1;
/*if (num[k] == num[k-1])
{
k = k + 1;
}*/
}
else if (sum < target)
{
k = k + 1;
/*if (num[k] == num[k-1])
{
k = k + 1;
}*/
}
else
{
t = t -1;
/*if (num[t] == num[t+1])
{
t = t - 1;
}*/
}
}
}
}
return result;
}
};
参考:几种字符串哈希函数