代码随想录算法训练营第六天LeetCode454,383,15,18

代码随想录算法训练营第六天|LeetCode454,383,15,18

LeetCode 454 四数相加II

题目链接:https://leetcode.cn/problems/4sum-ii/description/
//对排序无要求所以使用hash表
class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        //注意题目中的数组长度都是n
        int n = nums1.size();
        //能否将四个数组插入到一个数组中 //自己给自己提高难度。。。
        //两两数组比较更合适
        unordered_map<int,int> res; //key: a+b的数值; value: a+b数值出现的次数
        //遍历nums1和nums2数组,计算两个数组元素之和,以及和出现的次数
        for(int a : nums1){
            for(int b : nums2){
                res[a + b]++;
            }
        }

        int sum = 0;
        //遍历nums3和nums4数组,查找哈希表中有没有key值是(0 - (c + d))的,如果有,将value值计入sum中
        for(int c : nums3){
            for(int d : nums4){
                if(res.find(0 - (c + d)) != res.end()){
                    sum += res[0 - (c + d)];
                }
            }
        }
        return sum;

     
        
    }
};
视频讲解链接:https://www.bilibili.com/video/BV1Md4y1Q7Yh/?spm_id_from=333.788&vd_source=8d6cce160628d93add1e5fa9299f622d
文章讲解链接:https://programmercarl.com/0454.四数相加II.html

LeetCode 383 赎金信

题目链接:https://leetcode.cn/problems/ransom-note/description/
//使用hash表,因为对排序无要求,并且假设字符串都是小写字母
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        //注意:magazine 中的每个字符只能在 ransomNote 中使用一次
        //将magazine的字符插入map中
        unordered_map<int, int> res;
        for(auto &elem : magazine){
            res[elem - 'a'] ++;
        }
        //将ransomNote的字符与res表中的value进行比较
        for(auto &elem : ransomNote){
            if(res[elem - 'a'] == 0){
                return false;
            }
            else{
                res[elem - 'a'] --;
            }
        }
        return true;

    }
};
视频讲解链接:无
文章讲解链接:https://programmercarl.com/0383.赎金信.html

LeetCode 15 三数之和

题目链接:https://leetcode.cn/problems/3sum/description/
//使用双重循环和哈希表,条件很多,很容易写错
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        //注意:答案中不可以包含重复的三元组
        //哈希表法可以使用(0 - (a + b))的方法,但在vector中去重三元组非常麻烦
        vector<vector<int>> result; //保存三元组结果
        //使用set,既可以排序还能去重,但是set不能取下标
        //set<int> res(nums.begin(), nums.end()); 不能这样直接去重,假设三元组为[-4,2,2]

        //将nums排序
        sort(nums.begin(), nums.end());

        for(int i = 0; i < nums.size(); i++){
            if(nums[i] > 0) break;
            //做剪枝操作,采用nums[i] == nums[i-1]的操作是防止跳过[-1,-1,2]这样的数据
            if(i > 0 && nums[i] == nums[i-1]) continue;
            //三元组是不重复的,但单个三元组里可以包含重复的元素
            //设置一个哈希表
            unordered_set<int> set;
            for(int j = i + 1; j < nums.size(); j++){
                //做剪枝操作,采用该条件是防止跳过[-4,2,2]这样的数据
                if(j > i + 2 && nums[j-2] == nums[j-1] && nums[j-1] == nums[j]) continue;
                int c = 0 - (nums[i] + nums[j]);
                if(set.find(c) != set.end()){
                    result.push_back({nums[i], nums[j], c});
                    set.erase(c);
                }
                else{
                    set.insert(nums[j]);
                }


            }
        }
        return result;




    }
};
视频讲解链接:https://www.bilibili.com/video/BV1GW4y127qo/?spm_id_from=333.788&vd_source=8d6cce160628d93add1e5fa9299f622d
文章讲解链接:https://programmercarl.com/0015.三数之和.html#双指针
//使用双指针,去重难度降低
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        //使用双指针法比哈希表要方便
        //一个for循环,从下标0开始,定义left在i+1的位置,right在数组最右的位置
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());
        for(int i = 0; i < nums.size(); i++){
            //如果排序后的第一个元素大于0,可以直接跳出循环
            if(nums[i] > 0) break;
            //去重三元组第一个元素的方法
            if(i > 0 && nums[i] == nums[i-1]) continue;
          	//nums[i] + nums[left] + nums[right] ?= target
            int left = i + 1, right = nums.size() - 1; //这个要写外面。。。
            while(left < right){
                if(nums[i] + nums[left] + nums[right] > 0) right--;
                else if(nums[i] + nums[left] + nums[right] < 0) left++;
                else{
                    result.push_back({nums[i], nums[left], nums[right]});
                    //此处的去重逻辑 我认为定位了第一个元素nums[i],就可以直接判断nums[left]和nums[right]了
                    while(left < right && nums[right -1] == nums[right]) right--;
                    while(left < right && nums[left + 1] == nums[left]) left++;
                    //right左移,left右移,一个同时的收缩运动
                    right--;
                    left++;
                }
            }
            
        }
        return result;



    }
};

LeetCode 18 四数之后

题目链接:https://leetcode.cn/problems/4sum/description/
//双指针,基础和三数之和一样,因为要求四元组中的元素也各不相同所以更好写一点,别犯傻呗错误
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        //沿用之前三数之和的基础,多一层for循环
        //之前三元数组是单个可以存在重复的元素,本题要求元素互不相同
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());
        //第一次遍历
        for(int i = 0; i < nums.size(); i++){
            //考虑数组是[-4,-3,-2,-1] target = -10
            if(nums[i] > target && nums[i] >= 0) break;
            //对四元数组的第一个元素nums[i]去重
            if(i > 0 && nums[i] == nums[i-1]) continue;
            //第二次遍历
            for(int j = i + 1; j < nums.size(); j++){
                if((nums[i] + nums[j]) > target && (nums[i] + nums[j]) >= 0) break;
                //对四元数组的第二个元素nums[j]去重
                if(j > i + 1 && nums[j] == nums[j-1]) continue;

                //使用left和right
                //nums[i] + nums[j] + nums[left] + nums[right] = target
                int left = j + 1, right = nums.size() - 1;
                while(left < right){
                    //int left = j + 1, right = nums.size()-1; //error!傻逼错误,怎么写里面了
                    if((long)nums[i] + nums[j] + nums[left] + nums[right] > target) 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[right - 1] == nums[right]) right--;
                        while(left < right && nums[left + 1] == nums[left]) left++;
                        //left,right同时收缩
                        left++;
                        right--;
                    }
                }
                
            }
        }
        return result;
    }
};
视频讲解链接:https://www.bilibili.com/video/BV1DS4y147US/?spm_id_from=333.788&vd_source=8d6cce160628d93add1e5fa9299f622d
文章讲解链接:https://programmercarl.com/0018.四数之和.html
posted @ 2023-01-04 21:53  shadowbringerw  阅读(162)  评论(0)    收藏  举报