454.四数相加|383.赎金信|15.三数之和|18.四数之和

文章讨论了如何使用unordered_map数据结构解决四数之和问题,包括在代码中的遍历和去重策略,以及为何选择map而非其他数据结构。同时提到了空间消耗和避免数组越界的注意事项。
摘要由CSDN通过智能技术生成
  • 454.四数相加
    • 思路:
    • 类似于两数之和,不过是先两两数组间求出和,然后使用map来记录各个sum的频次;至于为什么不用set或者普通数组的原因也一致,因为要记录元素值和频次两个变量
    • 不同位置元素不论数值是否相等,符合要求就要加频次;第二个双层循环中对count并不是简单的自加一
    • 优化:(如下)
    • 第一个双层循环内部逻辑写复杂了
    • 双层循环可以用foreach
class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int, int> abNum;
        int count = 0;
        for (int i = 0; i < nums1.size(); i++) {
            for (int j = 0; j < nums2.size(); j++){
                int curSum = nums1[i] + nums2[j];
                if (abNum.find(curSum) != abNum.end()) {
                    abNum[curSum]++;
                }else {
                    abNum.insert(make_pair(curSum, 1));
                }
            }
        }
        for (int i = 0; i < nums3.size(); i++) {
            for (int j = 0; j < nums4.size(); j++) {
                int curSum = (0 - (nums3[i] + nums4[j]));
                if (abNum.find(curSum) != abNum.end()) {
                    count += abNum[curSum];
                }
            }
        }
        return count;

    }
};
  • 来源:代码随想录
class Solution {
public:
    int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
        unordered_map<int, int> umap; //key:a+b的数值,value:a+b数值出现的次数
        // 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中
        for (int a : A) {
            for (int b : B) {
                umap[a + b]++;
            }
        }
        int count = 0; // 统计a+b+c+d = 0 出现的次数
        // 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来。
        for (int c : C) {
            for (int d : D) {
                if (umap.find(0 - (c + d)) != umap.end()) {
                    count += umap[0 - (c + d)];
                }
            }
        }
        return count;
    }
};

  • 383.赎金信
    • 由于未看到题干中string只由小写字母组成,这里使用了map而不是数组,空间消耗更大些,但更适用
    • 对foreach的理解加深了
    • 注意看代码注释,第三个for循环处
    • 在C++中,对于一个未赋初值的 std::map,使用 map[key]++ 是合法的。这是因为,如果 key 在 map 中不存在,map[key] 会自动插入一个默认构造的值(对于 int 类型,默认是0),然后将其递增。如果 key 已经存在,那么它的值将被递增。
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        // int str1Num[26] = {0};
        unordered_map<char, int> _map;//初始值?
        for (int i = 0; i < ransomNote.size(); i++) {
            // str1[i - 'a']
            _map[ransomNote[i]]++;
        }
        for (char x : magazine) {
            _map[x]--;
        }
        for (auto x : _map) {//此时x自动判断为pair<char, int>,可以使用'.'访问键、值,此外map<key,value> _map,也可以使用_map.first/_map.second来访问;'->'适用于指针或迭代器
            if (x.second > 0)    return false;
        }
        return true;
    }
};
  • 15.三数之和
    • 二维vector赋值({ , , ,})
    • 去重操作
    • while内部双层判断的问题:若内层不加(left<right)这个条件可能会出现数组越界,这是由于本次循环的循环体可能在当前循环进入时合法的情况下,在本次循环体内出现了导致非法操作;eg:{0,0,0,0}
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;
        sort(nums.begin(), nums.end());
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] > 0)    return res;
            if (i > 0 && nums[i] == nums[i - 1]) continue;//i>0才能减防止数组越界
            int left = i + 1;
            int right = nums.size() - 1;
            while (left < right) {
                if (nums[i] + nums[left] + nums[right] < 0) {
                    left++;
                }else if (nums[i] + nums[left] + nums[right] > 0) {
                    right--;
                }else {//对left和right的去重应该在找到一组满足条件三元组后进行,最后不要忘记同时收缩,否则会死循环将当前三元组重复地插入vector
                    res.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 res;
    }
};
  • 18.四数之和
    • 主要在于剪枝与去重
    • 最内层的while逻辑还是会出错
    • 四数相加判断时需强转为long否则会溢出
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> res;
        sort(nums.begin(),nums.end());
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] > target && nums[i] > 0)    break;
            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;
                if (j > i + 1 && nums[j] == nums[j - 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)  left++;
                    else if ((long)nums[i] + nums[j] + nums[left] + nums[right] > target)  right--;
                    else {
                        res.push_back({nums[i],nums[j],nums[left],nums[right]});
                        // left++;
                        // right++; 
                        while (left < right && nums[right] == nums[right - 1])  right--;
                        while (left < right && nums[left] == nums[left + 1])    left++;
                        left++;
                        right--;
                    }


                }

            }
        }
        return res;
    }
};
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值