代码随想录算法训练营第七天

文章讲述了如何使用哈希表和双指针技巧解决四数之和问题,通过减少for循环层次,提高算法效率。首先统计两数之和出现次数,然后在后续数组中查找符合条件的组合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

继续疯狂补打卡中…

哈希表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;
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值