今日任务
454. 四数相加 II
主要思路:数据两两为一组计算
一个unordered_map,key放a和b两数之和,value 放a和b两数之和的负数(0-sum)出现的次数
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int, int> pairSum; //key = sum, val = 等于sum的个数
int len = nums1.size(), res = 0, tmp;
// nums1 与 nums2 一组
for (int i = 0; i < len; ++i) {
for (int j = 0; j < len; ++j) {
tmp = -(nums1[i] + nums2[j]);
if (!pairSum.count(tmp)) pairSum[tmp] = 1;
else ++pairSum[tmp];
}
}
for (auto c : nums3) {
for (auto d : nums4) {
tmp = c + d;
if (pairSum.count(tmp)) res += pairSum[tmp];
}
}
return res;
}
};
383. 赎金信
主要思路:先用unordered_map
计算存储每个字母在magazine
中出现次数,再遍历ransomNote
看其字母是否都可以被magazine
覆盖
第二次循环时如果c被check出来,那么其对应的出现次数-1,为0时将其从
unordered_map
中删掉
class Solution {
public:
// void toLowwerCase()
bool canConstruct(string ransomNote, string magazine) {
// transform(ransomNote.begin(), ransomNote.end(), ransomNote.begin(), ::tolowwer);
unordered_map<int, int> magCnt;
for (auto c : magazine) {
if (magCnt.count(c)) magCnt[c]++;
else magCnt[c] = 1;
}
for (auto c : ransomNote) {
if (!magCnt.count(c)) return false;
magCnt[c]--;
if (magCnt[c] == 0) magCnt.erase(c);
}
return true;
}
};
15. 三数之和
主要思路:先对数组排序,前一个数直接循环遍历,后两个数用指针
先剪枝再去重
然后记得这个题是返回的是元素本身而不是它们的下标
class Solution {
public:
// 记住,结果返回的是数字不是下标,别看错题
// 使用双指针, 设三个数分别位 a, b, c
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end()); // 原容器的顺序改变
int len = nums.size(), left, right, sum;
vector<vector<int>> res;
for (int i = 0; i < len; ++i) {
if (nums[i] > 0) return res; // 如果第一个元素已经大于0,那么不可能成为三元组,直接返回结果
// 首先对a去重
if (i > 0 && nums[i] == nums[i - 1]) continue;
left = i + 1, right = len - 1;
while (left < right) {
sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
res.push_back(vector<int>{nums[i], nums[left], nums[right]});
// 对b和c去重,此时应当在一个三元组第一次放入结果之后对b, c去重
while (left < right && nums[left] == nums[left + 1]) left++;
while (left > right && nums[right] == nums[right - 1]) right--;
// 找到答案时两个指针同时收缩
left++, right--;
} else if (sum > 0) {
right--;
} else {
left++;
}
}
}
return res;
}
};
18. 四数之和
主要思路:先对数组排序,前两个数直接用循环遍历,后两个数用双指针转化为O(n)
前两个循环可以先进行剪枝(也就是当数据已经来到正数,且前面的和的值已经大于0就不再往后计算)
然后记得对每个数进行去重
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
int len = nums.size();
for (int a = 0; a < len; ++a) {
if (nums[a] > target && nums[a] > 0) break;
if (a > 0 && nums[a] == nums[a - 1]) continue;
for (int b = a + 1; b < len; ++b) {
if (nums[a] + nums[b] > target && nums[a] + nums[b] >= 0) break;
// 给nums[b]去重
// 只需要单个位置的数前面相同时只出现一次即可,所以nums[a] == nums[b]是可以的,所以此处b > a + 1
if (b > a + 1 && nums[b] == nums[b - 1]) continue;
int left = b + 1, right = len - 1;
while (left < right) {
long sum = (long)nums[a] + nums[b] + nums[left] + nums[right];
if (sum > target) right--;
else if (sum < target) left++;
else {
res.push_back(vector<int>{nums[a], nums[b], nums[left], nums[right]});
while (left < right && nums[left] == nums[left + 1]) left++;
while (left < right && nums[right] == nums[right - 1]) right--;
left++, right--;
}
}
}
}
return res;
}
};