LeetCode 454四数相加II 383赎金信 15三数之和 18四数之和 | 代码随想录25期训练营day7

LeetCode 454 四数相加II 2023.10.31

  • 题目链接
  • 代码随想录讲解[链接]
    在这里插入图片描述
  • 题意:输入4个长度都为n的数组,判断任意四个元素分别来自4个不同的数组,求其和为0的组合次数
  • 方法:
    • 结合了1两数之和和242有效字母异位词的方法
    • 1两数之和考虑了两数之和等于一个目标值,用unordered_map结构判断当前遍历数组中元素与(target-当前值是否在无序映射中,在则记录答案,不在则将当前遍历元素插入无序映射中,第一题中是两个数的判断,本题是4个判断,所以先用unordered_map分别记录第一个和第二个数组、第三个和第四个数组中元素求和并记录该和组合的次数(这里参考了242有效字母异位词的方法),最后判断一个映射中的每个元素的相反数(和为0)是否在第二个映射中存在,如果存在则记录两个和的组合次数乘积,累计的次数即为题目答案
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
    //创建参数作为返回答案
    int num = 0;
    //创建两个无序映射用于分别记录第一个和第二个数组(第三个和第四个数组)元素的和及其组合的次数
    unordered_map<int, int> s1s2;
    unordered_map<int, int> s3s4;
    //开始记录,键(索引)为和,值为该和的组合次数
    for (int i = 0; i < nums1.size(); i++)
    {
        for (int j = 0; j < nums2.size(); j++)
        {
            s1s2[nums1[i]+nums2[j]]++;
            s3s4[nums3[i]+nums4[j]]++;
        }
    }
    //判断一个映射中所有元素的相反数是否在另一个映射出现过
    //如果出现则将两个和出现的次数相乘即为该组数据的组合次数,累加到num即为题解
    for (unordered_map<int, int>::iterator i = s1s2.begin(); i != s1s2.end(); i++)
    {
        if(s3s4.find(-(i->first)) != s3s4.end())
            num += i->second * s3s4.find(-(i->first))->second;
    }
    return num;
}

LeetCode 383 赎金信 2023.10.31

  • 题目链接
  • 代码随想录讲解[链接]
    在这里插入图片描述
  • 题意:输入两个字符串,判断其中第一个字符串的所有字符是否存在于第二个字符串中,包括字符和字符个数
  • 方法:典型的“键”(字符)“值”(出现次数)对问题,可以用哈希表完成,这里索引最大26个,所以优先选用数组,记录第一个字符串中每个字符的种类及其出现次数;然后遍历第二个字符串中的每个字符,当对应元素数组出现次数不为0时其值递减;最后遍历数组值是否都为0,存在不为0的说明第二个数组中有缺少
bool canConstruct(string ransomNote, string magazine) {
    //用数组存储ransomNote字符串中字符及其出现次数
    vector<int> result(26);
    for (int i = 0; i < ransomNote.size(); i++)
        result[ransomNote[i]-'a']++;
    //遍历magazine字符串中每个字符,判断数组中该字符出现次数是否为0
    //不为0则递减一次,继续遍历
    for (int i = 0; i < magazine.size(); i++)
    {
        if(result[magazine[i]-'a'] != 0)
            result[magazine[i]-'a']--;
    }
    //最后判断数组中元素是否都为0,存在不为0则返回false,说明缺失ransomNote中元素
    for (int i = 0; i < 26; i++)
    {
        if(result[i] != 0)
            return false;
    }
    //没有返回false则说明magazine包括了ransomNote中所有字符
    return true;
}

LeetCode 15 三数之和 2023.10.31

  • 题目链接
  • 代码随想录讲解[链接]
  • 题意:输入一个数组,求该数组中任意不同索引的三个数和为0,求这样的子数组集合
  • 方法:因为要求最终的数组,所以此处再用哈希表法考虑较多,不太合适;此处将数组排序后选用双指针法再遍历整个数组,需要注意两次去重,建议看代码随想录讲解视频[链接]或下面代码及注释
    在这里插入图片描述
vector<vector<int>> threeSum(vector<int>& nums) {
    //创建要返回的二维数组
    vector<vector<int>> result;
    //先将数组排序,方法用到了排序逻辑
    sort(nums.begin(), nums.end());
    //定义双指针变量,初始值分别设为0和最后的索引
    int left = 0, right = nums.size()-1;
    //开始遍历,这里left指针需指向当前遍历的下一个位置
    //所以避免越界,遍历最大位置在nums.size()-2
    for (int i = 0; i < nums.size()-1; i++)
    {
        //当遍历元素大于0时,后面元素都大于0,不可能和等于0
        if(nums[i] > 0)
            return result;
        //第一次去重判断上一个遍历的元素是否和现在遍历的元素相同
        if(i > 0 && (nums[i-1] == nums[i]))
            continue;
        //初始化左指针和右指针变量为当前遍历元素的下一位和数组最后一位
        left = i+1;
        right = nums.size()-1;
        //循环查找,条件:左指针小于右指针
        while (left < right)
        {
            //当三数值大于0,说明右指针的值大了,那么右指针左移
            if((nums[i]+nums[left]+nums[right]) > 0)
            {
                right--;
                continue;
            } 
            //当三数值小于0,说明左指针的值小了,那么左指针右移 
            else if((nums[i]+nums[left]+nums[right]) < 0)
            {
                left++;
                continue;
            }
            //当三值和等于0时,将答案数组填入result
            //第二次去重,去掉左右指针后相同元素(相同答案)的重复
            else
            {
                vector<int> temp;
                temp.push_back(nums[i]);
                temp.push_back(nums[left]);
                temp.push_back(nums[right]);
                result.push_back(temp);
                while(left < nums.size()-1 && nums[left] == nums[left+1])
                    left++;
                while(right > 0 && nums[right] == nums[right-1])
                    right--;
                //左指针右移,右指针左移,进行下次判断
                left++;
                right--;
            }
        }
    }
    return result;
}

LeetCode 18 四数之和 2023.10.31

  • 题目链接
  • 代码随想录讲解[链接]
    在这里插入图片描述
  • 题意:输入一个数组,求该数组中任意不同索引的四个数和为目标值target,求这样的子数组集合
  • 方法:延续15题求三数之和方法,加一层循环遍历数组固定一个数,求剩下三数之和为某一固定值,注意此时target可能为负数或者极大值剪枝以及定义变量类型需注意
vector<vector<int>> fourSum(vector<int>& nums, int target) {
    //定义最终返回答案的嵌套数组
    vector<vector<int>> result;
    //首先对数组进行排序
    sort(nums.begin(), nums.end());
    //创建左右指针变量并为其初始化
    int left = 0, right = nums.size()-1;
    //开始遍历数组,先固定第一个值
    for (int i = 0; i < nums.size()-1; i++)
    {
        //判断剪枝,target可能为负数,所以在target为正数时才能考虑剪枝
        if(target >= 0 && nums[i] > target)
            return result;
        //去重,与之前遍历过的比较
        if(i > 0 && nums[i-1] == nums[i])
            continue;
        //创建temp记录剩下三值为固定值,数值可能很大所以用long类型防止溢出
        long temp = target - nums[i];
        //开始遍历求剩下三值为固定值
        for (int j = i+1; j < nums.size()-1; j++)
        {
            //剪枝,当temp>0时
            if(temp >= 0 &&nums[j] > temp)
                break;
            //去重,需要加限制条件,在这个新的遍历中去重j>i+1
            if(j > i+1 && nums[j-1] == nums[j])
                continue;
            //初始化左右指针变量
            left = j+1;
            right = nums.size()-1;
            //左右指针移动计算,当左指针在右指针之前时
            while(left < right)
            {
                //和大于temp值时,需减小值,右指针左移
                if((long)nums[j]+nums[left]+nums[right] > temp)
                {
                    right--;
                    continue;
                }
                //和小于temp值时,需增大值,左指针右移
                else if((long)nums[j]+nums[left]+nums[right] < temp)
                {
                    left++;
                    continue;
                }
                //相等时,记录四值,并去后面的重
                else
                {
                    result.push_back(vector<int>{nums[i], nums[j], nums[left], nums[right]});
                    while (left < nums.size()-1 && nums[left] == nums[left+1])
                        left++;
                    while (right > j && nums[right] == nums[right-1])
                        right--;
                    left++;
                    right--;
                }
            }
        }
    }
    return result;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值