DAY7|哈希表Part2

454.四数相加II

没思路。。。不知道怎么用上哈希表
看题解

稀里糊涂写出来了

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        int n=nums1.size();
        unordered_map<int,int> myMap;
        for(int a:nums1){
            for(int b: nums2){
                myMap[a+b]++;
            }
        }
        int count=0;
        for(int c: nums3){
            for(int d: nums4){
                if(myMap.count(0-(c+d))!=0){
                    count+=myMap[0-(c+d)];
                }
            }
        }
        return count;
    }
};

不知道,感觉还要再总结一下这个题,现在脑子有点混乱,说不会吧,照着题解思路一路下来确实写出来了。说会吧,这个题给我一种二刷不一定能写对的没把握感(谁知道为什么会有这种感觉?)
时间复杂度O(N^2)

383. 赎金信

很容易有思路的一道题,思路就不再赘述。
贴一下我AC的版本

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int len=magazine.size();
        unordered_map<char,int> myMap;
        for(int i=0;i<len;++i){
            myMap[magazine[i]]++;
        }
        int len2=ransomNote.size();
        for(int i=0;i<len2;++i){
            if(myMap[ransomNote[i]]==0){
                return false;
            }
            else{
                --myMap[ransomNote[i]];
            }
        }
        return true;
    }
};

后知后觉发现我的提交时间占比很靠后,虽然已知力扣的那个统计数据不准确,但还是引起了我的注意。
看了一下题解,这里用数组会比哈希表更快,卡哥是这样写的:

一些同学可能想,用数组干啥,都用map完事了,其实在本题的情况下,使用map的空间消耗要比数组大一些的,因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的!数据量大的话就能体现出来差别了。 所以数组更加简单直接有效!

换数组写一下:

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

为了减少修改的部分直接把数组的名字叫myMap了
时间一下子快了起来
这里有一个26个字母直接得到数组下标的方法:
magazine[i]-‘a’

15. 三数之和

之前做过。。。隐约记得是没用哈希表的方法,其他的想不起来。
突然发现我之前还真是无效做题啊😭
看题解!

哈希表的题解,j剪枝的逻辑完全没看懂。
写双指针法吧,感叹一句好巧妙的去重逻辑!
思路大体如下:
先数组排序。
第一个指针为i,放在一个for循环从头开始循环,第二个指针取名left,起始位置在i的下一个,第三个指针取名right,起始位置在最大的位置。
求三者目前的和,如果和为正,说明最大的数取大了,right–;如果和为负,说明第二个指针取小了(为什么不是第一个指针?第一个指针是用来遍历整个数组的,是起点位置,相当于对整个数组的每一个数,在他右边所有的数中找出两个与他和为零的,这个过程需要遍历右边所有的可能的组合,所以在遍历结束之前(也就是right<=left之前)是不能改变i的 )(前面这段话有点赘述了,如果能理解为什么先移动第二个指针而不是第一个,就可以忽略不看)
此时移动第二个指针left++,直到能存在有和为0的情况,把这个情况存入result数组。
下面说一下在遍历的时候去重的思路:(真的很精妙)
在第一个指针循环的时候,如果此次循环结束进入下一个循环,发现下一个循环的第一个数与上一个循环第一个数相等,那么直接跳过这个数。也就是nums[i-1]==nums[i]的时候需要continue(此处注意i-1需要>=0)
为什么不是nums[i+1]==nums[i]?
注意第二个指针left是从i+1的位置开始的,如果是这种判断条件,相当于直接排除了所有第一个指针和第二个指针数相同的情况,这样会错过[-1,-1,2]的这种情况。
left和right去重,则是在循环中找到等于0的情况,下一步需要向内同时收缩left和right(此时如果left<right,第一个指针i还是不变的)。收缩的时候如果碰到相同的left或者right需要继续收缩以去重。
好了,上代码:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int left,right;
        int size=nums.size();
        vector<vector<int>> result;
        if(size<3) return result;
        sort(nums.begin(),nums.end());
        for(int i=0;i<size;++i){
            if(nums[i]>0) break;
            if(i>0 &&nums[i]==nums[i-1]) continue;
            left=i+1;
            right=size-1;
            while(right>left){
                int num=nums[i]+nums[left]+nums[right];
                if(num>0) --right;
                else if(num<0) left++;
                else{
                    result.push_back({nums[i],nums[left],nums[right]});
                    left++;
                    right--;
                    while(left<right && nums[left]==nums[left-1]) left++;
                    while(left<right && nums[right]==nums[right+1]) right--;
                }
            }
        }
        return result;
    }
};

时间复杂度O(N^2)
感觉是值得隔一段时间就刷几遍的题,防止忘记去重思路。
(哈希表方法有时间再看看 先挖个坑)

18 四数之和

先试着模仿上一道题的思路做了一下:

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> result;
        int left,right;
        int n=nums.size();
        sort(nums.begin(),nums.end());
        for(int i=0;i<n;++i){
            if(nums[i]>target && (target>0 || nums[i]>0)) break;
            if(i>0 && nums[i]==nums[i-1]) continue;
            for(int j=i+1;j<n;++j){
                if(nums[i]+nums[j]>target && nums[i]+nums[j]>=0) break;
                if(j>i+1 && nums[j]==nums[j-1]) continue;
                left=j+1;
                right=n-1;
                while(left<right){
                    long int sum=nums[i];
                    sum+=nums[j];
                    sum+=nums[left];
                    sum+=nums[right];
                    if(sum>target) right--;
                    else if(sum<target) left++;
                    else{
                        result.push_back({nums[i],nums[j],nums[left],nums[right]});
                        left++;
                        right--;
                        while(left<right && nums[left]==nums[left-1]) left++;
                        while(left<right && nums[right]==nums[right+1]) right--;
                    }
                }
            }
            
        }
        return result;
    }
};

看了一下题解,思路差不多是一样的,照着题解修改的是对于target的判断部分。
如果nums[i]大于target,不可以直接返回,因为可能存在[-4,-3,-2,-1]这种情况,
只有当nums[i]大于0的时候才可以break。
还有一个小的部分需要注意,计算sum的时候可能会溢出,需要用long int型变量。
而我一开始直接写的:
long int sum = nums[i] + nums[j] + nums[left] + nums[right];
还是会报错,于是我就选择了把四个累计加起来,第一种会报错的理由如下:
(因为gpt解释得很清楚所以我就直接贴上截图了)
long int溢出情况

  • 16
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值