• 代码随想录 | Day7


    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


    今日学习目标

    四数相加 II(454)
    赎金信(383)
    三数之和(15)
    四数之和(18)

    一、算法题

    1.四数相加 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

    示例 1:

    输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
    输出:2
    解释:
    两个元组如下:

    1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
    2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0

    代码:

    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;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.赎金信

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

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

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

    示例 1:

    输入:ransomNote = “a”, magazine = “b”
    输出:false

    代码:

    class Solution {
    public:
        bool canConstruct(string ransomNote, string magazine) {
            int hash[26] = {0};
            if(ransomNote.size() > magazine.size()) {
                return false;
            }
            for(int i = 0; i < magazine.length(); 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;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3.三数之和

    题目:
    给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

    你返回所有和为 0 且不重复的三元组。

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

    示例 1:

    输入:nums = [-1,0,1,2,-1,-4]
    输出:[[-1,-1,2],[-1,0,1]]
    解释:
    nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
    nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
    nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
    不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
    注意,输出的顺序和三元组的顺序并不重要。

    代码:

    class Solution {
    public:
        vector<vector<int>> threeSum(vector<int>& nums) {
            vector<vector<int>> result;
            sort(nums.begin(), nums.end());
            // 找出a + b + c = 0
            // a = nums[i], b = nums[j], c = -(a + b)
            for (int i = 0; i < nums.size(); i++) {
                // 排序之后如果第一个元素已经大于零,那么不可能凑成三元组
                if (nums[i] > 0) {
                    break;
                }
                if (i > 0 && nums[i] == nums[i - 1]) { //三元组元素a去重
                    continue;
                }
                unordered_set<int> set;
                for (int j = i + 1; j < nums.size(); j++) {
                    if (j > i + 2
                            && nums[j] == nums[j-1]
                            && nums[j-1] == nums[j-2]) { // 三元组元素b去重
                        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);// 三元组元素c去重
                    } else {
                        set.insert(nums[j]);
                    }
                }
            }
            return result;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    4.四数之和

    题目:
    给你一个由 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
    你可以按 任意顺序 返回答案 。

    示例 1:

    输入:nums = [1,0,-1,0,-2,2], target = 0
    输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

    代码:

    class Solution {
    public:
        vector<vector<int>> fourSum(vector<int>& nums, int target) {
            vector<vector<int>> result;
            sort(nums.begin(), nums.end());
            for (int k = 0; k < nums.size(); k++) {
                // 剪枝处理
                if (nums[k] > target && nums[k] >= 0) {
                	break; // 这里使用break,统一通过最后的return返回
                }
                // 对nums[k]去重
                if (k > 0 && nums[k] == nums[k - 1]) {
                    continue;
                }
                for (int i = k + 1; i < nums.size(); i++) {
                    // 2级剪枝处理
                    if (nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) {
                        break;
                    }
    
                    // 对nums[i]去重
                    if (i > k + 1 && nums[i] == nums[i - 1]) {
                        continue;
                    }
                    int left = i + 1;
                    int right = nums.size() - 1;
                    while (right > left) {
                        // nums[k] + nums[i] + nums[left] + nums[right] > target 会溢出
                        if ((long) nums[k] + nums[i] + nums[left] + nums[right] > target) {
                            right--;
                        // nums[k] + nums[i] + nums[left] + nums[right] < target 会溢出
                        } else if ((long) nums[k] + nums[i] + nums[left] + nums[right]  < target) {
                            left++;
                        } else {
                            result.push_back(vector<int>{nums[k], nums[i], nums[left], nums[right]});
                            // 对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;
        }
    };
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    学习及参考书籍

    代码随想录

  • 相关阅读:
    高性能分布式No SQL数据库Aerospike——常用工具使用
    【软件测试】资深测试聊,自动化测试分层实践,彻底打通高阶...
    客户管理系统 07FlyCRM是什么?
    [MT8766][Android12] 取消WIFI热点超过10分钟没有连接自动关闭设定
    Unity笔记(13):Android Movement of Characters[2D]
    Python标识符命名规范
    Nodejs中包的介绍及npm安装依赖包的多种方法
    Java编程案例:买飞机票
    力扣刷题训练(二)
    iOS开发Swift-类型转换
  • 原文地址:https://blog.csdn.net/CSDN_0853/article/details/134042567