描述
2数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
分析
- 不能重复利用相同的元素,那么需要对输入数组nums 排序,或者使用set来去重,本题中要求返回数组下标,则不能sort
- 简单的暴力求解: 2层循环,和target比较
- 左右指针,left 从左逼近,right从右逼近,线性时间复杂度,可以用来求解 具体的解集合,但是由于排序破坏了下标,故而无法使用
- 使用map来记录nums[index]需要的值和index
- 对于nums[i]的数,它需要的值是target - nums[i];
- 首先在map中查询是否有需要nums[i],如果有,则使用第一个作为解(为了去重而不继续使用其他的)
- 如果不在,把nums[i]需要的值注册进入map等待配对
算法
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> result;
vector<int> tmp;
unordered_multimap<int,int> hash;
for(int i =0;i < nums.size(); ++i){
if(hash.count(nums[i]) != 0){
auto it = hash.equal_range(nums[i]);
result.push_back(i);
result.push_back(it.first->second);
break;
}else{
hash.emplace(target-nums[i],i);
}
}
return result;
}
};
3数之和
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
分析
- 不重复且直接要求解集合,用sort升序列排列nums
- 对于 a + b + c = target 的题,可以变成 a + b = target -c ,用一个循环来遍历c,则在每次循环内部,target - c都是固定的,就变成在循环内部求解2数之和
- 需要适当的减枝(当c > target时,由于升序,不可能再有解,直接退出)
- 去重分2层,第一层c 去重,使用确保在c循环时,使用的数字都不同
- 第二层去重在循环内部求解2数之和
算法
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
if(nums.size() < 3) return result;
sort(nums.begin(),nums.end());
int target = 0;
for(int i = 0; i < nums.size() -1;++i){
// 减枝
if(nums[i] > target){
break;
}
//第一层c 去重,使用确保在c循环时,使用的数字都不同
if(i > 0 && nums[i] == nums[i -1]) continue;
int l = i + 1,r = nums.size() -1;
int t = target - nums[i];
while(l < r){
int sum = nums[l] + nums[r];
if(sum == t){
result.push_back(vector<int>{nums[i],nums[l],nums[r]});
//去重
while(l < r && nums[l] == nums[l+1]) l++;
l++;
//去重
while(l < r && nums[r] == nums[r-1]) r--;
r--;
}else if(sum > t){
while(l < r && nums[r] == nums[r-1]) r--;
r--;
}
else{
while(l < r && nums[l] == nums[l+1]) l++;
l++;
}
}
}
return result;
}
};
4数之和
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:答案中不可以包含重复的四元组。
分析
- 2层循环 + 左右指针
算法
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
typedef vector<vector<int>> ResultType;
typedef typename ResultType::value_type ValueType;
ResultType result;
sort(nums.begin(),nums.end()); // up
for(auto base = 0 ; base < nums.size(); ++base){
// 减枝
if(nums[base] > target/4) break;
//第一层去重
if(base > 0 && nums[base -1] == nums[base]) continue;
int sum = target - nums[base];
for(int j = base + 1; j < nums.size();++j){
// 减枝
if(nums[j] > sum/3) break;
//去重
if(j > base + 1 && nums[j] == nums[j-1]) continue;
int left = j+1,right = nums.size()-1,sub = sum - nums[j];
while(left < right){
if(nums[left] + nums[right] == sub){
result.emplace_back(ValueType{nums[base],nums[j],nums[left],nums[right]});
//去重
while(left < right && nums[left] == nums[left+1]) ++left;
while(left < right && nums[right] == nums[right-1]) --right;
++left;
--right;
}else if(nums[left] + nums[right] > sub){
while(left < right && nums[right] == nums[right-1]) --right;
--right;
}else{
while(left < right && nums[left] == nums[left+1]) ++left;
++left;
};
}
}
}
return result;
}
};