代码随想录打卡Day6

感觉今天很烧脑。。。主要是三数之和理解思路还有四数之和debug过程有点费劲。

454.四数相加II

这个只会暴力。。这个题目不需要去重(因为需要统计的是下标),而且只需要返回符合条件的元组个数,看完视频讲解以后直接就做出来了,这个题目的关键点在于两两分组,前两组构造出一个哈希表,后两个数组用两层for循环遍历就可以,在符合条件的时候注意个数不应该加1,而是加上哈希表中对应存储的值。
这是我的代码。

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int, int> umap;
        int result = 0;
        for(int i = 0; i < nums1.size(); i++){
            for(int j = 0; j < nums2.size(); j++)
                umap[nums1[i] + nums2[j]] ++;
        }
        for(int i : nums3){
            for(int j : nums4){
                if(umap.find(0 - i - j) != umap.end()) //配对成功
                    result += umap[0 - i - j];
                
            }
        }
        return result;
    }
};

383. 赎金信

这题比较简单,有了之前的 242.有效的字母异位词基础,做这道题很快,思路是一样的。用一个大小为26的整型数组统计magazine中各个字母出现的次数,然后在遍历ransomNote的时候自减就可以。唯一要注意的点就是在最后判断整个数组的值的时候,当各个值都大于等于0时即可满足要求,但凡出现一个负数,都不符合要求,这个之前的有效的字母异位词判断条件有所不同。
这是我的代码

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int hash[26] = {0};  //全部初始化为0
        for(char c : magazine)
            hash[c - 'a'] += 1;
        for(char c : ransomNote)
            hash[c - 'a'] -= 1;
        for(int i : hash){
            if(i < 0)
                return false;
        }
        return true;
    }
};

15. 三数之和

这道题果断听劝,没有用哈希法去做,老老实实去看视频,但是在看视频的时候还是感觉理解起来有点困难,回放了几次才彻底弄明白。这道题需要去重,对遍历的nums[i]、nums[left]、nums[right]都需要去重,注意,在找到符合条件的元组后,还需要对left和right进行去重,去重后此时left和right实际上还指向本次的结果,一定要记得在去重之后再对left加一,对right减一,否则会陷入死循环,我就吃了这个亏,用VS debug才发现问题所在。。
这是我的代码

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());  //对nums进行升序排序
        for(int i = 0; i < nums.size(); i++){
            if(nums[i] > 0) 
                return result;
            if(i > 0 && nums[i] == nums[i - 1])  //对nums[i]去重
                continue;
            int left = i + 1;
            int right = nums.size() - 1;
            while(left < right){
                if(nums[i] + nums[left] + nums[right] < 0)  //和小了,left偏移
                    left++;
                else if(nums[i] + nums[left] + nums[right] > 0)  //和大了,right偏移
                    right--;
                else{  //恰好符合
                    result.push_back({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;
    }
};

18. 四数之和

这道题目比上一道题还要难。。。。但是思路大体差不多,我还是看了视频,主要是将这一题的nums[i] + nums[j]当成上一题的nums[i]就行了,大体的代码写起来很快,但是还有一些细节需要注意。
在双重for循环遍历数组时,需要在两重循环中都做一个去重操作,在内层循环中,i是不变的,主要是对j进行探索,但是经过一轮内层循环后,如果该位置的值和上一轮循环的值相同的话,就没必要继续了,应该直接continue;同理对于外层循环也需要对nums[i]去重。还有一些剪枝操作,但是这道题的判定条件要复杂一些,如果目标值是负数的话,nums[i] + nums[j] > target不能用来作为跳过的条件,因为后面可能还有负数,直接跳过的话可能错过符合条件的元组。但是有一些情况是可以跳过的,例如target > 0,而nums[i] + nums[j]已经大于target且nums[j] >= 0。
反正这道题我还是做了几十分钟。。最后还被一个很大很大的测试样例给恶心了。。记得及时强制类型转换为long int。。。
这是我的代码

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());  //将nums升序排列
        for(int i = 0; i < nums.size(); i++){
            if(i > 0 && nums[i] == nums[i - 1])
                continue;
            for(int j = i + 1; j < nums.size(); j++){
                if (j > i + 1 && nums[j] == nums[j - 1])
                    continue;
                if(nums[i] + nums[j] > target && nums[j] >= 0)  //没有必要继续找
                    break;
                int left = j + 1;
                int right = nums.size() - 1;
                while(left < right){
                    if((long int)nums[i] + (long int)nums[j] + (long int)nums[left] + (long int)nums[right] < target) //和小了,left右移
                        left++;
                    else if((long int)nums[i] + (long int)nums[j] + (long int)nums[left] + (long int)nums[right] > target) //和大了,right左移
                        right--;
                    else{  //找到符合条件的结果
                        result.push_back({nums[i], nums[j], 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;
    }
};
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值