代码随想录算法训练营15期 Day7 | 454.四数相加II、 383. 赎金信 、15. 三数之和、18. 四数之和

目录

力扣 454.四数相加II

题解:哈希表-map-unordered_map

力扣 383.赎金信

题解1:暴力解法 

题解2:哈希表--数组 

力扣 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

题解:哈希表-map-unordered_map

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        std::unordered_map<int,int> map;//定义一个映射map,用于后面存放
        for(int a:nums1){//c++快速遍历写法,相当于for(int i = 0;i < nums1.size();i++)
            for(int b:nums2){
                map[a + b]++;//将数组nums1和nums2中的a与b求和,作为键(key),通过map访问改键对应的值,并将其加1(value++),统计a+b数值出现的次数
            }
        }
         int count = 0 ;//设置count,用于后面符合元祖的统计
         for(int c:nums3){
             for(int d:nums4){
                 if(map.find(0 - (c + d)) != map.end()){//直接判断map中有无(0-(c+d))的值,若有,直接
                     count += map[0 - (c + d)];//后项为出现(0-(c+d))的次数
                 }
             }
         }
         return count;
    }
};

力扣 383.赎金信

题目:

给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false 。

magazine 中的每个字符只能在 ransomNote 中使用一次。

提示:

  • 1 <= ransomNote.length, magazine.length <= 105
  • ransomNote 和 magazine 由小写英文字母组成

题解1:暴力解法 

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        for(int i = 0; i < magazine.length() ; i++){//暴力解法,分别遍历杂志与赎金信中所以字母元素。
            for(int j = 0 ;j < ransomNote.length() ; j++){//外循环为杂志,内循环为赎金信。目的就是为了迎合题意,赎金信中的元素都要在杂志中,且每个字母只能用一次。
                if(magazine[i] == ransomNote[j]){//如果当前赎金信元素等于当前杂志元素
                    ransomNote.erase(ransomNote.begin() + j);//直接使用erase操作符,删去当前赎金信元素
                    break;//直接跳出内存循环,遍历下一个赎金信值
                }
            }
        }
        if(ransomNote.length() == 0){//如果遍历结束,赎金信中无元素,说明赎金信中所有元素都在杂志中存在
                return true;//返回true
            }
            return false;//否则返回false
    }
};

题解2:哈希表--数组 

注意第二个for循环中的if判断语句,很细节!

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int record[26] = {0};//定义一个长度为26的数组,初始值设置为0,用来后面存储数据。
        for(int i = 0 ;i < magazine.length();i++){//遍历杂志中小写字母中的个数,分别存入对应的元素中,并使用++来计数。
            record[magazine[i] - 'a']++;
        }
        for(int j = 0; j < ransomNote.length() ; j++){//遍历赎金信中小写字母的个数,分别存入对应的元素中,并使用--来计数
            record[ransomNote[j] - 'a']--;
            if(record[ransomNote[j] - 'a'] < 0){//如果在第二层for循环中,任何时间出现record数组某一元素的个数小于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 且不重复的三元组。

注意:答案中不可以包含重复的三元组

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;//表示一个二维整数向量,即一个向量的向量。用来存放产生的三元组
        sort(nums.begin(),nums.end());//先讲原数组就行快速排序
        for(int i = 0 ; i < nums.size() ; i++){
            if(nums[i] > 0){//若在将数组顺序排序后,第一个值就大于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) right--;//大于0,右指针自减,和减小
                else if( nums[i] + nums[left] + nums[right] < 0) left++;//小于0,左指针自加,和增大
                else{ 
                    result.push_back(vector<int>{nums[i],nums[left],nums[right]});//在获取第一组三元数组后对b、c进行去重
                    while(right > left && nums[right] == nums[right - 1]) right--;//对c去重
                    while(right > left && nums[left] == nums[left + 1]) left++;//对b去重
                    right--;
                    left++;
                }
            }
        }
        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
你可以按 任意顺序 返回答案 

题解:双指针法

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> result;
        sort(nums.begin(),nums.end());
        for(int i = 0 ;i < nums.size();i++){
            if(nums[i] > target && nums[i] >= 0){//剪枝-剪去nums[i] >= 0部分
                break;
            }
            if(i > 0 && nums[i] == nums[i - 1]){//去重第一个元素
                continue;
            }
            for(int k = i + 1; k < nums.size();k++){
                if(nums[i] + nums[k] > target && nums[i] + nums[k] >= 0){
                    break;
                }
                if(k > i + 1 && nums[k] == nums[k - 1]){
                    continue;
                }
                int left = k + 1;
                int right = nums.size() - 1;//双指针代表第3、4个元素,在集合中移动
                while(right > left){
                    if(nums[i] + nums[k] + nums[left] + nums[right] > target ){
                        right--;
                    }else if(nums[i] + nums[k] + (nums[left] + nums[right]) < target ){
                        left++;
                    }else{
                        result.push_back(vector<int>{nums[i],nums[k],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;
    }
};

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值