算法训练营Day6
454.四数相加II,383. 赎金信 ,15. 三数之和,18. 四数之和
题目
454.四数相加II
题目链接:https://leetcode.cn/problems/4sum-ii/description/
文章讲解:https://programmercarl.com/0454.%E5%9B%9B%E6%95%B0%E7%9B%B8%E5%8A%A0II.html
思路
分组+哈希表
和两数相加差不多的思路,只不过两数相加用哈希表存下标,这道题用哈希表存数量;先分成两组,第一组两两相加,用哈希存储可能的和以及出现的次数;在第二组中两两相加的过程中判断是否有满足target的情况,如果有则加上出现的次数
代码
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int, int> hashTable1, hashTable2;
int count = 0;
for(int i = 0; i < nums1.size(); i ++){
for(int j = 0; j < nums2.size(); j ++){
hashTable1[nums1[i] + nums2[j]] ++;
}
}
for(int i = 0; i < nums3.size(); i ++){
for(int j = 0; j < nums4.size(); j ++){
if(hashTable1.find(- nums3[i] - nums4[j]) != hashTable1.end()) count += hashTable1[- nums3[i] - nums4[j]];
}
}
return count;
}
};
383. 赎金信
题目链接:https://leetcode.cn/problems/ransom-note/description/
文章讲解:https://programmercarl.com/0383.%E8%B5%8E%E9%87%91%E4%BF%A1.html
思路
哈希表
要在magazing中找ransomNote,所以要将magazine中的字符数量存在哈希表中,然后遍历ransomNote,让其对应的字符数量减少1,如果字符数小于0则返回false(字符数不够或者不存在该字符)
代码
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
unordered_map<char, int> hashTable;
for(int i = 0; i < magazine.length(); i ++){
hashTable[magazine[i]] ++;
}
//要在magazing中找ransomNote
for(int i = 0; i < ransomNote.length(); i ++){
hashTable[ransomNote[i]] --;
if(hashTable[ransomNote[i]] < 0) return false;
}
return true;
}
};
15. 三数之和
题目链接:https://leetcode.cn/problems/3sum/description/
文章讲解:https://programmercarl.com/0015.%E4%B8%89%E6%95%B0%E4%B9%8B%E5%92%8C.html
思路
没想出来,看题解
重点在于数组不重复
排序+双指针:对于三个不同的数,a、b、c只要满足每次a<b<c即可保证数组不重复,剩下的只要满足每个数不和前一个数相同即可,这样每个位置的数只会取到一次
代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size(); i ++){
if(nums[i] > 0) break;
if(i > 0 && nums[i] == nums[i - 1]) continue;
int j = i + 1, k = nums.size() - 1;
while(j < k){
int sum = nums[i] + nums[j] + nums[k];
if(sum < 0){
j ++;
while(j < k && nums[j] == nums[j - 1]) j ++;
}
else if(sum > 0){
k --;
while(j < k && nums[k] == nums[k + 1]) k --;
}
else{
res.push_back({nums[i], nums[j], nums[k]});
j ++;
while(j < k && nums[j] == nums[j - 1]) j ++;
k --;
while(j < k && nums[k] == nums[k + 1]) k --;
}
}
}
return res;
}
};
18. 四数之和
题目链接:https://leetcode.cn/problems/4sum/
文章讲解:https://programmercarl.com/0018.%E5%9B%9B%E6%95%B0%E4%B9%8B%E5%92%8C.html
思路
没思路,看了题解说用三数之和的写法做,再加上剪枝
报错一直找不到问题,原来题目没说nums.size()一定大于4,要判断一下不然报错越界
还有就是sum的值过大,相加的话要转成long long
代码
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> res;
if(nums.size() < 4) return res;
sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size() - 3; i ++){
if(nums[i] > target && nums[i] >= 0) break;
if(i > 0 && nums[i] == nums[i - 1]) continue;
for(int j = i + 1; j < nums.size() - 2; j ++){
cout << i << ' ' << j << endl;
long long temp = nums[i] + nums[j]; //防止溢出
if(temp > target && temp >= 0) break;
if(j > i + 1 && nums[j] == nums[j - 1]) continue;
int left = j + 1, right = nums.size() - 1;
while(left < right){
long long sum = (long long)nums[i] + nums[j] + nums[left] + nums[right];
if(sum < target){
left ++;
while(left < right && nums[left] == nums[left - 1]) left ++;
}
else if(sum > target){
right --;
while(left < right && nums[right] == nums[right + 1]) right --;
}
else{
res.push_back({nums[i], nums[j], nums[left], nums[right]});
left ++;
while(left < right && nums[left] == nums[left - 1]) left ++;
right --;
while(left < right && nums[right] == nums[right + 1]) right --;
}
}
}
}
return res;
}
};