【吃饭香系列】二周目|代码随想录算法训练营第七天|454.四数相加II |383. 赎金信 |15. 三数之和 |18. 四数之和
第三章 哈希表part02
一、核心目标
今天我们的核心任务是掌握:
● 454.四数相加II
● 383. 赎金信
● 15. 三数之和
● 18. 四数之和
454.四数相加II
建议:本题是 使用map 巧妙解决的问题,好好体会一下 哈希法 如何提高程序执行效率,降低时间复杂度,当然使用哈希法 会提高空间复杂度,但一般来说我们都是舍空间 换时间, 工业开发也是这样。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0454.四数相加II.html
cpp
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map <int,int> sum1;//key:a+b的数值,value:a+b数值出现的次数
for(int a:nums1)// 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中
{
for(int b:nums2)
sum1[a+b]++;
}
int count=0;// 统计a+b+c+d = 0 出现的次数,里面的(0-(c+d))是找出map中相同的key
for(int c:nums3)// 再遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来。
for(int d:nums4)
if(sum1.find(0-(c+d))!=sum1.end())
count+=sum1[(0-(c+d))];
return count;
}
};
383. 赎金信
建议:本题 和 242.有效的字母异位词 是一个思路 ,算是拓展题
题目链接/文章讲解:https://programmercarl.com/0383.赎金信.html
cpp
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int record[26]={0};
if(ransomNote.size()>magazine.size())
return false;
for(int i=0;i<magazine.size();i++)
record[magazine[i]-'a']++;
for(int j=0;j<ransomNote.size();j++)
{
record[ransomNote[j]-'a']--;
if(record[ransomNote[j]-'a']<0)
return false;
}
return true;
}
};
总结
有效的字母异位词 一个类型。都是哈希数组另放,然后范围大的样例数组先在哈希里++,范围小的--,发现负数就说明不匹配。
- 三数之和
建议:本题虽然和 两数之和 很像,也能用哈希法,但用哈希法会很麻烦,双指针法才是正解,可以先看视频理解一下 双指针法的思路,文章中讲解的,没问题 哈希法很麻烦。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0015.三数之和.html

cpp
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(),nums.end());
//剪枝
for(int i=0;i<nums.size();i++)
{
if(nums[i]>0)
return result;
//正确去重不会漏掉-1,-1,2 这种情况
if(i>0&&nums[i]==nums[i-1])
continue;
int left=i+1;
int right=nums.size()-1;
while(right>left)
{
if(nums[i]+nums[left]+nums[right]>0)right--;
else if(nums[i]+nums[left]+nums[right]<0)left++;
else
{
result.push_back(vector<int>{nums[i],nums[left],nums[right]});
while(right>left&&nums[right]==nums[right-1])right--;
while(right>left&&nums[left]==nums[left+1])left++;
right--;
left++;
}
}
}
return result;
}
};
总结
- 四数之和
建议: 要比较一下,本题和 454.四数相加II 的区别,为什么 454.四数相加II 会简单很多,这个想明白了,对本题理解就深刻了。 本题 思路整体和 三数之和一样的,都是双指针,但写的时候 有很多小细节,需要注意,建议先看视频。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0018.四数之和.html
cpp
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> result;
sort(nums.begin(),nums.end());
for(int k=0;k<nums.size();k++)
{
if(nums[k]>target&&target>0)
break;
if(k>0&&nums[k]==nums[k-1])
continue;
for(int i=k+1;i<nums.size();i++)
{
if(nums[k] + nums[i] > target && nums[k] + nums[i] >= 0)
break;
if(i>k+1&&nums[i]==nums[i-1])
continue;
int left=i+1;
int right=nums.size()-1;
while(left<right)
{
if((long)nums[k]+nums[i]+nums[left]+nums[right]>target) right--;
else if((long)nums[k]+nums[i]+nums[left]+nums[right]<target) left++;
else
{
result.push_back(vector<int>{nums[k],nums[i],nums[left],nums[right]});
while(left<right&&nums[right]==nums[right-1])right--;
while(left<right&&nums[left]==nums[left+1])left++;
right--;
left++;
}
}
}
}
return result;
}
};
总结
在三数之和上面多套了一层循环,容易出现以下问题
1、

2、
