第七天打卡(注意哈希和双指针)

一、四数相加

1、力扣题目

题目链接:454. 四数相加 II - 力扣(LeetCode)

2、视频学习

视频链接:学透哈希表,map使用有技巧!LeetCode:454.四数相加II_哔哩哔哩_bilibili

思路解析:该题既需要数组中的值还需要数组中的下标,并且是在数组中找某些元素,所以可以考虑使用map。并且可以重复,最后仅需返回count的值。

该题需要注意的是两两分组,计算第一组所出现的和以及出现的次数,并放入map,遍历第二组时就仅需查找与题目条件所对应需要的值是否在map中出现过即可,次数相加就是最终的结果。

代码如下:

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int,int> map;
        int count=0;
        for(int i=0;i<nums1.size();i++){
            for(int j=0;j<nums2.size();j++){
                int key=nums1[i]+nums2[j];//前两个相加
                auto iter=map.find(key);
                if(iter==map.end()){
                    map.insert(pair<int,int>(key,1));//未找到则插入
                }
                else{
                    iter->second+=1;
                }
            }
        }//获取了第一个和第二个数组的和的值和出现次数

        for(int i=0;i<nums3.size();i++){
            for(int j=0;j<nums4.size();j++){
                int key=0-(nums3[i]+nums4[j]);
                auto iter=map.find(key);
                if(iter!=map.end()){
                    count+=iter->second;//对应value相加
                }
            }
        }
        return count;
    }
};

3、总结

注意该题与后面的三和四题的区分,因为涉及到两个数的计算,所以考虑使用map,且不用考虑重复

二、赎金信

1、力扣题目

题目链接:383. 赎金信 - 力扣(LeetCode)

2、文章学习

思路解析:其实比较简单,跟上一篇第一题思路类似,建议自己写一下。

代码如下:

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int hash[26]={0};
        for(int i=0;i<magazine.size();i++){
            hash[magazine[i]-'a']+=1;
        }
        for(int i=0;i<ransomNote.size();i++){
            hash[ransomNote[i]-'a']-=1;
        }
        for(int i=0;i<sizeof(hash)/sizeof(hash[0]);i++){
            if(hash[i]<0)return false;
        }
        return true;

    }
};

三、三数之和

1、力扣题目

题目链接:15. 三数之和 - 力扣(LeetCode)

2、视频学习

视频链接:梦破碎的地方!| LeetCode:15.三数之和_哔哩哔哩_bilibili

思路解析:该题主要是为了跟上面第一题进行区分,该题最好使用双指针法,因为涉及到去重,hash不太好去重,而且题目要求返回的是值而非下标,所以此时数组顺序是可以打乱的,在排序之后的数组中找值,就会想到使用双指针

首先遍历一遍数组作为a的值,然后对a进行去重操作,此时去重逻辑是数组是排过序的,相同的值都集中在一圈,因而如果当前a跟上一个a相等则重复

选定a之后,b和c使用双指针进行寻找,即nums[left] + nums[right] = -a时的left和right,之后对b和c进行去重,此时的去重逻辑就是如果当前的left或者right跟上一个left或者right相等,则移动left或right指针。注意是while而非if,因为可能出现多个相同的值在一起,要判断多次。

注意当指针找到一个符合要求的b和c之后不能使用break切断循环,而应该两个指针一起向内移动一步,因为判断条件时b+c的和,而该和可能有各种b和c组成,所以最终的停止条件应该是不满足left<right,即整个遍历一遍之后退出。

代码如下:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(),nums.end());//排序
        if(nums[0]>0)return {};//返回空

        vector<vector<int>> result;
        for(int i=0;i<nums.size();i++){//选取a
            int target=0-nums[i];
            
            int left=i+1,right=nums.size()-1;//双指针

            if(i>0&&nums[i]==nums[i-1])continue;//去重a

            while(left<right){
                int value=nums[left]+nums[right];//需要找的数之和

                //未找到则移动指针
                if(value<target){left++;}
                else if(value>target){right--;}
                //找到则判重
                else{
                    result.insert(result.end(),{nums[i],nums[left],nums[right]});
                    //对b和c的去重,此时b为left,c为right
                    while(left<right&&nums[left]==nums[left+1]){left++;}
                    while(left<right&&nums[right]==nums[right-1]){right--;}

                    left++;
                    right--;
                    //注意是移动指针,而不是break,因为判断的是之和,后面可能还会有和相等的情况
                }
            }
        }
        return result;
    }
};

3、总结

该题最终结果只与值有关,而且需要进行去重,对数组下标无要求,因而考虑双指针

四、四数之和

1、力扣题目

题目链接:18. 四数之和 - 力扣(LeetCode)

2、视频学习

视频链接:难在去重和剪枝!| LeetCode:18. 四数之和_哔哩哔哩_bilibili

思路解析:该题思路跟上一题思路一致,可以自己写一下,然后我的代码没有进行剪枝,可以自己进行改进。

代码如下:

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());//排序

        vector<vector<int>> result;
        if(nums.size()<4)return result;//不符合条件的返回空

        for(int i=0;i<nums.size();i++){
            
            if(i>0&&nums[i-1]==nums[i])continue;//a去重

            for(int j=i+1;j<nums.size();j++){
              
                if(j>i+1&&nums[j]==nums[j-1])continue;//b去重

                int left=j+1;
                int right=nums.size()-1;
                while(left<right){
                    long sum=(long)nums[i]+nums[j]+nums[left]+nums[right];//注意类型转化
                    if(sum<target)left++;
                    else if(sum>target)right--;
                    else{
                        result.insert(result.end(),{nums[i],nums[j],nums[left],nums[right]});
                        
                        while(left<right&&nums[left]==nums[left+1])left++;//c去重
                        while(left<right&&nums[right]==nums[right-1])right--;//d去重

                        left++;
                        right--;
                    }
                }

            }
        }
        return result;
    }
};

3、总结

该题与上题思路一致,可以加深印象

五、总结

当题目中涉及在数值中查某元素是否存在,或者满足条件的元素时,考虑使用hash或者双指针。如果是没有涉及到的下标的数组,可以考虑排序后用双指针,如果题目强调了排序的数组,那么基本上就是双指针,其余情况有优先考虑hash。在选择用哈希表是,也要注意不同的题目选用不同的数据结构。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值