454.四数相加II
链接:[454.四数相加II](https://leetcode.cn/problems/4sum-ii/)
思路
两两分组,通过两组互为相反数的性质,通过unordered_map进行计数
知识积累
map.at(key)++ 能够通过map进行计数
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int, int>sum12;
unordered_map<int, int>sum34;
for (int i : nums1) {
for (int j : nums2){
if (sum12.find(i + j) == sum12.end()){
sum12.insert(make_pair(i + j, 1));
}
else {
sum12.at(i + j)++;
}
}
}
int count = 0;
for (int i : nums3){
for (int j : nums4){
if (sum12.find(0 - (i + j)) != sum12.end()){
count += sum12.at(0 - (i + j));
}
}
}
// for (auto [sum, times] : sum12){
// if (sum34.find(0 - sum) != sum34.end()){
// count += times * sum34.at(0 - sum);
// }
// }
return count;
}
};
383. 赎金信
思路
通过unordered_map进行计数
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
unordered_map<char,int>mag;
for (char c : magazine){
if (mag.find(c) == mag.end()){
mag.insert(make_pair(c, 1));
}
else {
mag.at(c)++;
}
}
for (char c : ransomNote){
if (mag.find(c) == mag.end()){
return false;
}
else {
mag.at(c)--;
if (mag.at(c) < 0) return false;
}
}
return true;
}
};
15. 三数之和
思路
如果三元组中三个数的顺序不同但是数值相同仍然算作相同的组合,这种情况下想要去重就比较麻烦。自然而然考虑到用字典排序的方式来确定三元组,重复的三元组在字典序下一定是相同的。此外,题目对三元组的顺序没有要求,所以考虑先将数组进行排序,这样按顺序得到的三元组就是字典序的。在数组有序的情况下,假定第一个数固定,那么另外两个之和就是个固定值,另外两个会在这个固定值的一半两侧分布,就会想到另外两个数从两侧相互靠近,也就是双指针的想法,只需要确定好移动指针的策略即可。当两者之和大于固定值,大的值需要减少,right–,反之亦然。重要的是考虑向灯时候该如何处理:相等时我们需要将结果存下,同时要考虑不要重复添加。在两数确定的情况下,其实第三个数也确定,所以这两个数都不用考虑已经出现的值,所以两者都得移动。假定只有一个是已经出现的值,那么最终和肯定不会为target,也就归为前面的情况。我这里用temp来保存上一步的值。也可以用while循环来跳过相同值,但一定要注意while中要考虑边界条件,也就是大循环中的小循环仍然要满足大循环的条件防止越界访问。同时还要注意left < right && nums[left] == nums[left + 1] 中left < right一定要放在前面。
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 temp = INT_MAX;
for (int k = 0; k < nums.size() - 2; ++k){
if (nums[k] == temp) continue;
// 不要重新申明变量
temp = nums[k];
int temp1 = INT_MAX;
int temp2 = INT_MAX;
int i = k + 1;
int j = nums.size() - 1;
while (i < j && i < nums.size()){
if (nums[i] + nums[j] + nums[k] > 0){
--j;
}
else if (nums[i] + nums[j] + nums[k] < 0){
++i;
}
else {
if (nums[i] != temp1 && nums[j] != temp2) {
vector<int>item;
item.push_back(nums[k]);
item.push_back(nums[i]);
item.push_back(nums[j]);
result.push_back(item);
temp1 = nums[i];
temp2 = nums[j];
}
--j;
++i;
}
}
//排除相同元
}
return result;
}
};
18. 四数之和
思路
思路上和三数之和一致,只是需要多考虑一个数所以需要多一层外循环。
尤其需要注意:小循环要保证大循环的前提成立
left < right && nums[left] == nums[left+1]
与 nums[left] == nums[left + 1] && left < right 区别
一定要先满足边界条件
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>>result;
if (nums.size() < 4) return result;
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); ++i){
if (i > 0 && nums[i] == nums[i - 1]) continue;
for (int j = i + 1; j < nums.size(); ++j){
if (j > i+1 && nums[j] == nums[j - 1]) continue;
int left = j + 1;
int right = nums.size() - 1;
while (left < right) {
long sum = (long)nums[i] + nums[j] + nums[left] + nums[right];
// 数据比较大的多个数相加时要考虑是否会溢出
if (sum == target){
vector<int>item;
item.push_back(nums[i]);
item.push_back(nums[j]);
item.push_back(nums[left]);
item.push_back(nums[right]);
result.push_back(item);
// 小循环要保证大循环的前提成立
// left < right && nums[left] == nums[left + 1]
// nums[left] == nums[left + 1] && left < right 区别
//一定要先满足边界条件
while(left < right && nums[left] == nums[left + 1]) {
left++;
}
left++;
while(left < right && nums[right] == nums[right - 1]){
right--;
}
right--;
}
else if (sum > target){
right--;
}
else if (sum < target){
left++;
}
}
}
}
return result;
}
};