代码随想录算法训练营第7天 | LeetCode454 四数相加||,383 赎金信,15 三数之和,18 四数之和

@代码随想录算法训练营第7天 | LeetCode454 四数相加||,383 赎金信,15 三数之和,18 四数之和(四数之和有一些代码细节进行了系统的注释,建议复习的时候查看一下)

454 四数相加||

视频链接:
https://programmercarl.com/0024.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.html

第一遍读题思考(五分钟内,如果没有思路就写暴力解法思路,暴力解法思路也不清晰就写无

只能想到暴力法n的四次方时间复杂度。

代码随想录解法思路

可以简化到n的平方,用两个二重循环分别计算两对数组的加和的值存储在两个hash map中,这里map中的key存储加和的值,value用来存储这个key出现了多少次。

c++代码具体实现注意事项

map可以像数组用方括号直接访问,但是比数组要方便,可以直接对之前没有添加过的key所对应value进行操作,初始value就是0.

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        std::unordered_map<int, int> sum1;
        for(int a:nums1)
            for(int b:nums2){
                sum1[a+b]++;
            }
        int count{0};
        for(int c:nums3)
            for(int d:nums4){
                auto iter = sum1.find(0-c-d);
                if(iter!=sum1.end()){
                    count += iter->second;
                }
            }
        
        return count;
    }
};

学习时长

25分钟

383 赎金信

第一遍读题思考(五分钟内,如果没有思路就写暴力解法思路,暴力解法思路也不清晰就写无

用map做哈希表,然后先把magazine里的字母都统计到map中,然后再遍历ransomnote中的字母,找到就减减,然后查看所有key有没有对应的value小于0的。

代码随想录解法思路

不用map,用26大小的数组,因为map操作消耗更多,只有小写字母。

c++代码具体实现注意事项

map可以像数组用方括号直接访问,但是比数组要方便,可以直接对之前没有添加过的key所对应value进行操作,初始value就是0.
注意只用了两个for循环,把原本的检验hash小于0的步骤直接放在第二个循环里了。

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']++;
        }
        for(int i=0;i<ransomNote.size();i++){
            hash[ransomNote[i]-'a']--;
            if(hash[ransomNote[i]-'a']<0){
                return false;
            }
        }
        return true;
    }
};

学习时长

14分钟

15 三数之和

第一遍读题思考(五分钟内,如果没有思路就写暴力解法思路,暴力解法思路也不清晰就写无

双重for循环边遍历边更新hash表,但是这样好像会存在重复的数组。

代码随想录解法思路

非常巧妙,用双指针法。一个基本for循环产生a,然后left指针指向a右边一个数,right指针指像数组最末尾,然后判断a+left+right是否等于0,如果等于0,left和right同时收缩,如果大于0,right收缩,如果小于0,left收缩。如此一来便收集了以a为基底的所有组合。但是记得要对left和right进行去重,left找到以后检查left的右边是否相同,right亦然。同样对基底a也要进行去重,检查a和a-1是否相同,相同直接continue。
最最重要的一点,前面这个方法成立完全基于数组是排好顺序的。

双指针法yyds!!!!!!

c++代码具体实现注意事项

注意去重操作,这里在遍历的时候去重就不需要在结果中去重了。

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        std::sort(nums.begin(), nums.end());

        for(int i=0;i<nums.size();i++){
            if(i==0 && nums[i]>0){
                return result;
            }
            if(i>0 && nums[i]==nums[i-1]){
                continue;
            }
            int left = i+1;
            int right = nums.size()-1;
            while(right>left){
                if(nums[i]+nums[left]+nums[right]<0){
                    left++;
                }
                else if(nums[i]+nums[left]+nums[right]>0){
                    right--;
                }
                else{
                    result.push_back(vector<int>{nums[i], nums[left], nums[right]});
                    while(right>left && nums[right]==nums[right-1]){right--;}
                    while(right>left && nums[left] == nums[left+1]){left++;}
                    right--;
                    left++;
                }
            }
        }
        return result;
    }
};

学习时长

40分钟

18 四数之和

第一遍读题思考(五分钟内,如果没有思路就写暴力解法思路,暴力解法思路也不清晰就写无

感觉可以用一个二重循环生成一个map的哈希表,然后再去找,不过感觉去重非常复杂。

代码随想录解法思路

延续三数之和的思想,仍然采用双指针法,只不过基底指针采用了双重循环。要对两次循环进行两级剪枝操作,用于剔除异常数据。
此外最开始应该进行判断如果数组长度小于4曾直接返回。
最后,还需要注意四个数相加可能溢出的情况,需要转换成long类型,查看下面的代码看注释标注的地方。

c++代码具体实现注意事项

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

        if(nums.size()<4){ // 小于长度4的数组直接进行返回
            return result;
        }
        for(int i=0;i<nums.size()-3;i++)
            for(int j=i+1;j<nums.size()-2;j++){ // 两重循环,基底有两个,所以要进行分别剪枝和去重操作
                if(nums[i]>target && target>=0){ // 一级剪枝注意这道题里的target可能是负数,所以单纯的大于target是不可以的
                    break;
                }
                if(i>0 && nums[i] == nums[i-1]){ // 一级去重操作,新的基底要与之前的基底进行比较
                    continue;
                }
                if(nums[i]+nums[j]>target && target>=0){ // 二级剪枝操作注意这里两个基底为一个整体进行判断
                    break;
                }
                if(j>i+1 && nums[j] == nums[j-1]){ // 二级去重操作注意,第二个基底是在第一个基底基础上选择的,所以不是大于1!!!
                    continue;
                }
                int left = j+1;
                int right = nums.size()-1;
                while(left<right){
                    if((long) nums[i]+nums[j]+nums[left]+nums[right]>target){ // 注意int类型的数相加会溢出的问题
                        right--;
                    }
                    else if((long) nums[i]+nums[j]+nums[left]+nums[right]<target){
                        left++;
                    }
                    else{
                        result.push_back({nums[i],nums[j],nums[left],nums[right]});
                        while(left<right && nums[left+1]==nums[left]){left++;}
                        while(left<right && nums[right-1]==nums[right]){right--;}
                        left++;
                        right--;
                    }
                }
        }
        return result;
    }
};

学习时长

40分钟

哈希表总结

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,使得子数组的和大于等于给定的目标值。这里可以使用滑动窗口的方法来解决问题。使用两个指针来表示滑动窗口的左边界和右边界,通过移动指针来调整滑动窗口的大小,使得滑动窗口中的元素的和满足题目要求。具体实现的代码如下: ```python def minSubArrayLen(self, target: int, nums: List[int]) -> int: left = 0 right = 0 ans = float('inf') total = 0 while right < len(nums): total += nums[right] while total >= target: ans = min(ans, right - left + 1) total -= nums[left] left += 1 right += 1 return ans if ans != float('inf') else 0 ``` 以上就是第二十二算法训练营的内容。通过这些题目的练习,可以提升对双指针和滑动窗口等算法的理解和应用能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值