【Leetcode】求和问题专题
Author: Xin Pan
Date: 2022.4.27
这次总结一类问题即 求和问题的解法。包括如下具体题目:
接下来开始正文内容。
【1】两数之和
输入: 输入的是一个非排序的数组nums
,和一个目标值target
。
输出:和为target
的元素的下标。
解析
因为输入是没有排序的数组,所以不能用双指针的做法处理,因为双指针没有回退的操作(这里回退是说指针往初始的方向走,或者说我不知道下一个需要找的值在当前指针左侧或者右侧,这里请仔细体会)。因而我们使用一个hashmap
来解决这个问题。
我的答案
class Solution
{
public:
vector<int> twoSum(vector<int> &nums, int target)
{
int nnum = nums.size();
unordered_map<int, int> map;
map[nums[0]] = 0;
for (int i = 1; i < nnum; i++)
{
unordered_map<int, int>::iterator iter = map.find(target - nums[i]);
if (iter != map.end())
{
return {i, iter->second};
}
else
{
map[nums[i]] = i;
}
}
return {-1, -1};
}
};
【167】两数之和 II - 输入有序数组
输入:非递减顺序排序的数组nums
和一个目标值target
。
输出:和为target
的元素的下标。
解析
现在的输入数组是排序过的,因此我们使用双指针的解法来处理,为什么这里可以使用双指针解法?
因为考察头指针,如果nums[头指针]+nums[尾指针]<target
那我们知道头指针需要右移,右边肯定是不小于左边的值的。尾指针适用同样的道理。
我的答案
class Solution
{
public:
vector<int> twoSum(vector<int> &numbers, int target)
{
int nl = 0, nr = numbers.size() - 1;
while (nl < nr)
{
int ntmp = numbers[nl] + numbers[nr];
if (ntmp < target)
{
nl++;
}
else if (ntmp > target)
{
nr--;
}
else
{
return {nl + 1, nr + 1};
}
}
return {-1, -1};
}
};
【15】三数之和
输入:输入的是一个非排序的数组nums
。目标值target=0。
输出:输出和为0的不重复三元组。
解析
这个题的输入也是非排序的数组。但是做法和之前的两数之和又不一样,区别在于。不能出现重复的三元组,那么如果按着之前两数之和的做法求排列再去做去重,它的时间复杂度大概是 O ( N 3 ) O(N^3) O(N3)。那么我们如何处理好不重复现在看来就是关键了。
对于不重复:
- 第二个元素不小于第一个元素;
- 第三个元素不小于第二个元素。
这样就可以了即(第一个元素<=第二个元素<=第三个元素)。
答案
class Solution
{
public:
vector<vector<int>> threeSum(vector<int> &nums)
{
int nnum = nums.size();
vector<vector<int>> vecret;
sort(nums.begin(), nums.end());
for (int one = 0; one < nnum; one++)
{
if (one > 0 && nums[one] == nums[one - 1])
{
continue;
}
int three = nnum - 1, ntgt = -nums[one];
for (int two = one + 1; two < nnum; two++)
{
if (two > one + 1 && nums[two] == nums[two - 1])
{
continue;
}
while (two < three && nums[two] + nums[three] > ntgt)
{
three--;
}
if (two == three)
{
break;
}
if (nums[two] + nums[three] == ntgt)
{
vecret.push_back({nums[one], nums[two], nums[three]});
}
}
}
return vecret;
}
};
【18】四数之和
输入:输入的是一个非排序的数组nums
,和目标值target。
输出:输出和为target
的不重复四元组。
解析
其实这个题和三数之和是完全一样的做法。如果三数之和理解了,那这题就回了;否则回头重新想想三数之和怎么做。
本题相比三数之和多了一个循环而已。
答案
class Solution
{
public:
vector<vector<int>> fourSum(vector<int> &nums, int target)
{
int nnum = nums.size();
sort(nums.begin(), nums.end());
vector<vector<int>> vecret;
for (int one = 0; one < nnum; one++)
{
if (one > 0 && nums[one] == nums[one - 1])
{
continue;
}
for (int two = one + 1; two < nnum; two++)
{
if (two > one + 1 && nums[two] == nums[two - 1])
{
continue;
}
int ntgt = target - nums[one] - nums[two];
int four = nnum - 1;
for (int three = two + 1; three < nnum; three++)
{
if (three > two + 1 && nums[three] == nums[three - 1])
{
continue;
}
while (three < four && nums[three] + nums[four] > ntgt)
{
four--;
}
if (three == four)
{
break;
}
if (nums[three] + nums[four] == ntgt)
{
vecret.push_back({nums[one], nums[two], nums[three], nums[four]});
}
}
}
}
return vecret;
}
};