给定一个整数数组,返回两个数的下标位置,他们加起来是一个指定目标值。
你应该认为每个输入恰有一个解决方案。
例子:
给定num =(2、7、11、15),目标值= 9,
因为num[0]+ num[1]= 2 + 7 = 9,
所以返回[0,1]。
更新(2016/2/13):
返回的格式已经改变了从零开始的索引。请仔细阅读上述更新描述。
分析:DONE
其实比较简单的解法是在遍历数组时,总是在每个元素后面的所有元素中,即[i+1,n)的范围内寻找target-nums[i]这个值,如果存在这个值则返回下标i个这个值的下标即可。时间浮渣度为O(n^2),空间复杂度为O(1)。
但是,比较显然的是可以用哈希map来加速查找(因为他是常数时间的查找),此时可以往前找也可以往后搜索目的值,方案如下:
一直遍历数组
1)在哈希map中寻找target-nums[i]
2)如果存在则返回这对下标,否则压入nums[i]到哈希map中
空间复杂度为O(N),时间浮渣度为O(N),通过所有测试案例耗时16ms
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
//于2016.6.10徒手重写
map<int,int> mapping;
vector<int> result;
for(int i=0;i<nums.size();i++)
{
if(mapping.find(target-nums[i])!=mapping.end() )
{
result.push_back(mapping[target-nums[i]]);
result.push_back(i);
return result;
}
mapping[nums[i]]=i;
}
return result;
}
};
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)
分析:
暴力破解,时间复杂度是O(n^3),超时
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
if(nums.size()<=2)
return result;
int pos1=0,pos2=0,pos3=0;
for(;pos1<nums.size();pos1++)
{
pos2=pos1+1;
for(;pos2<nums.size();pos2++)
{
pos3=pos2+1;
for(;pos3<nums.size();pos3++)
{
if((nums[pos1]+nums[pos2]+nums[pos3])==0)
{
vector<int> tmpres;
tmpres.push_back(nums[pos1]);
tmpres.push_back(nums[pos2]);
tmpres.push_back(nums[pos3]);
sort(tmpres.begin(),tmpres.end());
result.push_back(tmpres);
}
}
}
}
return result;
}
};
别人的做法:
本体只需要找到三个数相加=0,那么只需要在遍历数组元素时,另外两个加起来等于负的当前元素即可。
然后利用双指针查找这样的两个元素。
关键词:先排序,再遍历,双指针,防重复操作。
class Solution {
public:
vector<vector<int> > threeSum(vector<int> &num) {
int n = num.size();
sort(num.begin(), num.end());//排序
vector<vector<int> > res;
for(int i = 0; i < n-2; i++)
{
if(i > 0 && num[i] == num[i-1])
continue;//重复的元素不用计算
int target = num[i];
twoSum(num, i+1, -target, res);//从当前元素后面开始找相加为目标值(当前元素的负值)的两个数字
}
return res;
}
void twoSum(vector<int> &sortedNum, int start, int target, vector<vector<int> >&res)
{
int head = start, tail = sortedNum.size() - 1;
while(head < tail)
{
int tmp = sortedNum[head] + sortedNum[tail];
if(tmp < target)
head++;
else if(tmp > target)
tail--;
else//相等,获取结果
{
res.push_back(vector<int>{sortedNum[start-1], sortedNum[head], sortedNum[tail]});
//为了防止出现重复结果,跳过相等的情况
int k = head+1;
while(k < tail && sortedNum[k] == sortedNum[head])
k++;
head = k;
k = tail-1;
while(k > head && sortedNum[k] == sortedNum[tail])
k--;
tail = k;
}
}
}
};
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).
分析:
a+b+c尽可能接近target,那么如前面一题所示,当遍历到元素a时,
我们在其后寻找b和c之和接近target-a的两个数即可。而尽可能接近的标准就是两者之差尽可能小。
基于上面一题的提示,这个题就简单很多了,如代码所示:
class Solution {
public:
int threeSumClosest(vector<int>& num, int target) {
int n = num.size();
sort(num.begin(), num.end());//排序
int result=0, min_gap=INT_MAX;
for(int i = 0; i < n-2; i++)
{
if(i > 0 && num[i] == num[i-1])
continue;//重复的元素不用计算
int tmptarget =target - num[i];
if(twoSum(num, i+1, tmptarget, result,min_gap)) //从当前元素后面开始找相加接近目标值的两个数字之和
break;
}
return result;
}
bool twoSum(vector<int> &sortedNum, int start, int tmptarget, int &result,int &min_gap)
{
int head = start, tail = sortedNum.size() - 1;
while(head < tail)
{
int tmp = sortedNum[head] + sortedNum[tail]; //tmp要尽可能接近tmptarget,甚至相等
if(tmp < tmptarget)
{
if(min_gap > abs(tmptarget-tmp))
{
min_gap=abs(tmptarget-tmp);
result=sortedNum[start-1]+ sortedNum[head]+ sortedNum[tail];
}
head++;
}
else if(tmp > tmptarget)
{
if(min_gap > abs(tmptarget-tmp))
{
min_gap=abs(tmptarget-tmp);
result=sortedNum[start-1]+ sortedNum[head]+ sortedNum[tail];
}
tail--;
}
else//相等,相差距离绝对最短,直接获取结果退出即可。
{
result=sortedNum[start-1]+ sortedNum[head]+ sortedNum[tail];
return true;
}
}
return false;
}
};
18. 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)
分析:
与前面的题类似,不在累述!
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& num, int target) {
int n = num.size();
if(n < 4)
return result;
sort(num.begin(), num.end());//排序
for(int i = 0; i < n-3; i++)
{
for(int j=i+1;j<n-2;j++)
{
int tmptarget =target - num[i]-num[j];
twoSum(i,num, j+1, tmptarget);//从当前元素后面开始找相加接近目标值的两个数字之和
while(j < n-2&&num[j+1]==num[j])//防重复答案
j++;
}
while(i < n-3 && num[i+1]==num[i])//防重复答案
i++;
}
return result;
}
void twoSum(int i,vector<int> &sortedNum, int start, int target)
{
int head = start, tail = sortedNum.size() - 1;
while(head < tail)
{
int tmp = sortedNum[head] + sortedNum[tail];
if(tmp < target)
head++;
else if(tmp > target)
tail--;
else//相等,获取结果
{
result.push_back(vector<int>{sortedNum[i],sortedNum[start-1], sortedNum[head], sortedNum[tail]});
//为了防止出现重复结果,跳过相等的情况
int k = head+1;
while(k < tail && sortedNum[k] == sortedNum[head])
k++;
head = k;
k = tail-1;
while(k > head && sortedNum[k] == sortedNum[tail])
k--;
tail = k;
}
}
}
private:
vector<vector<int>> result;
};
注:本博文为EbowTang原创,后续可能继续更新本文。如果转载,请务必复制本条信息!
原文地址:http://blog.csdn.net/ebowtang/article/details/50320391
原作者博客:http://blog.csdn.net/ebowtang
本博客LeetCode题解索引:http://blog.csdn.net/ebowtang/article/details/50668895