代码随想录训练营day06(哈希表)
454.四数相加II
题目
题意:nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0,与四数之和区分。
解题方法(map)
流程:
1、遍历A、B
2、umap的key存放a+b之和(涉及到查找),value存放a+b之和出现的次数
3、遍历C、D
4、使用map.find查找(0-c-d),如果找到了,次数count加上对应的value
难点(想不到如何处理4个数)
- 巧妙:把四数相加变成了两数相加
- 为什么用map:除了key,还需要用value存a+b之和出现的次数
- 巧妙:umap[a+b]++;
key(索引)存a+b之和,value(能修改的值)是a+b之和出现的次数
- 犯错:以为会漏算,其实不会(因为遍历了C、D,只要符合情况都会加上)
例如:(c+d)出现了3次,(a+b)出现了4次,实际上count会在三轮不同的循环中+4+4+4
代码
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int,int>umap;
for(int a:nums1){
for(int b:nums2){
umap[a+b]++;//巧妙:key是a+b数值,value是a+b出现的次数
}
}
int count = 0;//要输出的数量
int find_num = 0;//要查找的数值
for(int c:nums3){
for(int d:nums4){
find_num = 0-(c+d);
if(umap.find(find_num) != umap.end()){
count+=umap[find_num];
}
}
}
return count;
}
};
383. 赎金信
题目
思考历程
类似 242.有效的字母异位词
解题方法(数组)
- 题目关键:不可重复使用、只有小写字母
- 核心:涉及到26个小写字母,使用数组建立哈希关系(数组下标为各字母,数组内容为字母出现次数)
- 流程:
1、magazine往数组里加次数
2、ransomNote往数组里减次数
3、只要出现次数小于0说明false了
难点
感悟:什么时候用数组建立哈希关系
像只有26个小写字母这种少量、连续的数据时使用数组。数组下标充当key,数组内容充当value。key是可以直接当索引被查找的,value的内容是我们可以修改的。
- 如
record[magazine[i] - 'a']++;
中,数组下标[magazine[i] - 'a']
代表某一个小写字母,++可以修改该位置的value
代码
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int record[26]={0};//怎么知道是数组还是数组元素呢
//magazine往里加
for(int i=0;i<magazine.size();i++){
record[magazine[i] - 'a']++;
}
//ransomNote往里减(因为只能使用一次),遇到负数说明失败了
for(int j=0;j<ransomNote.size();j++){
record[ransomNote[j] - 'a']--;
if(record[ransomNote[j] - 'a']<0){
return false;
}
}
return true;
}
};
15. 三数之和
题目
重复的三元组:
[-1, 0, 1]与[1, -1, 0]与[0, -1, 1]等,本题先排序,然后对a、b、c用不同的方法去重
思考历程
- 知道重复的三元组是什么意思(答案如上所示)
- 不知道和四数相加题目有什么区别(本题是1个数组内部找3个数相加,需要考虑重复情况;四数相加题目是4个独立数组分别找1个数出来相加,不用考虑重复情况)
解题方法(双指针法)
核心:a+b+c=0
令遍历变量i=a,b从i+1位置开始,c从数组末尾开始,寻找当前a合适的(a,b,c)
解题流程:
- 对a去重:nums[i]不能等于nums[i-1],前者三元组的集合是后者的真子集
- 收获第一个结果
- 对b去重:nums[left]不能等于nums[left+1],若等,left+1,
- 对c去重:nums[right]不能等于nums[right-1],若等,right-1
- left右移,right左移,缩小范围
难点(abc的去重)
- 如何分配abc,三者如何去重
- 犯错:漏了第一处的while(right>left),这是一个循环,直到left与right相遇,本i的任务才结束
- 漏了第二处的while(right>left),因为left与right已改变,所以需要重新判断
- 去重后还需left++; right–;原因是去重后,nums[left]的值与收获结果时nums[left]的值相等,并未右移,right同理
代码
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++){//遍历变量i即a
if(nums[i]>0){
return result;
}
if(i>0 && nums[i] == nums[i-1]){//对a去重
continue;
}
int left = i+1;//b出现
int right = nums.size()-1;//c出现
while(right>left){
if(nums[i]+nums[left]+nums[right]>0) right--;
else if(nums[i]+nums[left]+nums[right]<0) left++;
else{//a+b+c=0 找到一个结果了
result.push_back(vector<int>{nums[i],nums[left],nums[right]});
while(right > left && nums[left]==nums[left+1]) left++;//对b去重
while(right > left && nums[right]==nums[right-1]) right--;//对c去重
//找到答案时,双指针同时收缩
left++;
right--;
}
}
}
return result;
}
};
18. 四数之和
题目
思考历程
解题方法
难点
代码
在这里插入代码片