继续疯狂补打卡中…
哈希表part02
454 四数相加II
题目
给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:
0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
思路
暴力解法是直接四层for循环,但是估计会超时。
现在我们用哈希表来减少for循环的层数:
1、首先定义 一个unordered_map,key放a和b两数之和,value 放a和b两数之和出现的次数。
2、遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中。
3、定义int变量count,用来统计 a+b+c+d = 0 出现的次数。
4、在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。
5、最后返回统计值 count 就可以了
代码
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int, int> map;
int result=0;
for(int i=0; i<nums1.size(); i++){
for(int j=0; j<nums2.size(); j++){
map[nums1[i]+nums2[j]]++;
}
}
for(int c:nums3){
for(int d:nums4){
if(map.find(0-c-d)!=map.end()){
result+=map[0-c-d];
}
}
}
return result;
}
383 赎金信
题目
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote中使用一次。
思路
因为magazine 中的每个字符只能在 ransomNote中使用一次,所以需要用map来记录字符以及字符出现的次数,不要求字符有序,所以使用unordered_map。
先使用unordered_map来统计magazine中各个字符出现的次数,然后遍历ransomNote,若遍历到的字符在unordered_map中,则次数减去1,若次数小于0,则说明ransomNote不能由magazine里面的字符构成。
代码
bool canConstruct(string ransomNote, string magazine) {
if(magazine.size()<ransomNote.size()) return false;
unordered_map<char, int> map;
for(char ch:magazine){
map[ch]++;
}
for(char ch:ransomNote){
map[ch]--;
if(map[ch]<0){
return false;
}
}
return true;
}
15 三数之和
题目
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
思路
使用双指针。三个数使用双指针,那么就要先固定一个数(遍历nums),然后剩下两个数使用双指针。难点在于去重,代码随想录中对去重细节讲解得很好,这里不再赘述。
代码
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> result;
for(int i=0; i<nums.size(); i++){
while(i>0&&(i<nums.size()-2)&&nums[i]==nums[i-1]) i++; //去重
int remaining=0-nums[i];
int left=i+1, right=nums.size()-1;
while(left<right){
if(nums[left]+nums[right]>remaining){
right--;
}else if(nums[left]+nums[right]<remaining){
left++;
}else{
while(left<right&&nums[left]==nums[left+1]) left++;
while(left<right&&nums[right]==nums[right-1]) right--;
result.push_back({nums[i], nums[left], nums[right]});
left++;
right--;
}
}
}
return result;
}
18 四数之和
题目
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
思路
和上一题:三数之和的思路一样,不过是加了一层for循环,去重细节在代码随想录中讲解得很详细,这里不再赘述。
代码
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&&nums[k]>=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[left]==nums[left+1]){
left++;
}
while(left<right&&nums[right]==nums[right-1]){
right--;
}
left++;
right--;
}
}
}
}
return result;
}