首页 > 编程语言 >代码随想录算法训练营第七天| 454.四数相加II 383. 赎金信 15. 三数之和 18. 四数之和

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

时间:2024-01-30 19:55:57浏览次数:191  
标签:vector 四数 15 nums int 随想录 ch right left

454.四数相加II  

给你四个整数数组 nums1nums2nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

0 <= i, j, k, l < n

nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

题目链接:454. 四数相加 II - 力扣(LeetCode)

思路:当遇到需要确认元素是否重复出现的问题时,考虑用map哈希解决问题。将前两个数组的和存入map1,并用value表示这个和出现的对数。然后查询-(num3[k]+nums4[l])是否出现在map中。

注意:

用insert方法重复插入同一key值的键值对并不会导致覆盖,即会插入失败。

用find方法查找元素会比count方法快很多。

用下标访问map,即使改下标下没有内容,我们也能对value进行访问,不用区别对待。

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        map<int,int> map1;
        int count=0;
        for(int i=0;i<nums1.size();i++){
            for(int j=0;j<nums2.size();j++){
//                auto iter=map1.find(nums1[i]+nums2[j]);
//                if(iter!=map1.end())
//                if(map1.count(nums1[i]+nums2[j]))
                map1[nums1[i]+nums2[j]]++;
//                else
//                map1.insert(pair<int,int>(nums1[i]+nums2[j],1));       //无需区别对待
//                map1.insert(pair<int,int>(nums1[i]+nums2[j],1));
            }
        }

            for(int k=0;k<nums3.size();k++){
                for(int l=0;l<nums4.size();l++){
 //                   auto iter=map1.find(-(nums3[k]+nums4[l]));
//                    if(iter!=map1.end()){
                    if(map1.find(0-(nums3[k]+nums4[l]))!=map1.end()){
                        count+=map1[0-(nums3[k]+nums4[l])];
                    }
                }
            }
            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. 赎金信  

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

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

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

题目链接:383. 赎金信 - 力扣(LeetCode)

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        map<char,int>map1;
        map<char,int>map2;
        for(char ch:ransomNote){
            map1[ch]++;
        }
        for(char ch:magazine){
            map2[ch]++;
        }
        for(char ch:ransomNote){
            if(map1[ch]>map2[ch])
            return false;
        }
    return true;
    }
};

更好的写法:

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        // 利用哈希表
        unordered_map<char,int> u_m;

        for(auto ch:magazine)
            ++u_m[ch];

        for(auto ch:ransomNote)
        {
            if(u_m[ch]==0)
                return false;
            
            --u_m[ch];
        }

        return true;
    }
};

15. 三数之和  

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

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

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

题目链接:15. 三数之和 - 力扣(LeetCode)

思路:正常哈希法会很困难,因为去重的操作很复杂。用双指针法可以有效的解决这个问题。同时,用sort函数先排序原数据的思想要学会(双指针法是一定要排序的)。尽管要求三元组不能重复,但注意三元组内部可以重复,因此在去重a时要注意,要比较a的上一个元素而非a的下一个元素。

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){
                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[right]+nums[left]>0)
                {
                    right--;
                }
            else if(nums[i]+nums[right]+nums[left]<0)
            {
                left++;
            }
            else{

                result.push_back(vector<int>{nums[i],nums[left],nums[right]});    
                while(right>left&&nums[right]==nums[right-1])right--;        //b、c去重
                while(right>left&&nums[left]==nums[left+1])left++;
            right--;                                                        //找到答案在移动b、c
            left++;
            }
            }
        }
        return result;
    }
};

18. 四数之和 

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • abc 和 d 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

题目链接:18. 四数之和 - 力扣(LeetCode)

思路:和三数之和思路类似,只是从左动右固定变成左右都动。注意,左边的去重一定要在右边移动之前进行,否则会被[0,0,0,0]判溢出。

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> result;
        if(nums.size()<4){
         return result;
        }
        sort(nums.begin(),nums.end());

        for(int i=0;i<nums.size()-3;i++){
            if(nums[i]>target&&nums[i]>=0)
                break;
            if(i>0&&nums[i]==nums[i-1]){
                continue;
            }                                    //左侧去重必须在for之前进行
            for(int j=nums.size()-1;j>=i+3;j--){
            if(j<nums.size()-1&&nums[j]==nums[j+1]){
                continue;
            }
            int left=i+1;
            int right=j-1;
            while(right>left){
                if((long)nums[i]+nums[left]+nums[right]+nums[j]>target)right--;
                else if((long)nums[i]+nums[left]+nums[right]+nums[j]<target)left++;
                else{
                    result.push_back(vector<int>{nums[i],nums[left],nums[right],nums[j]});
                    while(right>left&&nums[right]==nums[right-1])right--;
                    while(right>left&&nums[left]==nums[left+1])left++;
                    left++;right--;
                }
            }

            }
        }
        return result;
    }
};

 

标签:vector,四数,15,nums,int,随想录,ch,right,left
From: https://www.cnblogs.com/Liubox/p/17997839

相关文章

  • 15大主流平台私域引流SOP整理
    一切生意的本质都是流量”这句话每个生意人都要牢牢记住。只有获取足够多的足够精准的流量,才能达成一个私域的良好的发展:吸粉-信任-转化-裂变,如此循环往复。那么自己的项目又适合在哪个平台去做引流?哪个平台有哪些需要注意的地方以及可以设置钩子的场地?小红书、芝乎、V博、tie吧、t......
  • 151. 反转字符串中的单词(中)
    目录题目法一、双指针法二、字符串常用操作题目给你一个字符串s,请你反转字符串中单词的顺序。单词是由非空格字符组成的字符串。s中使用至少一个空格将字符串中的单词分隔开。返回单词顺序颠倒且单词之间用单个空格连接的结果字符串。注意:输入字符串s中可能会......
  • 代码随想录算法训练营第六天 |242. 有效的字母异位词 349. 两个数组的交集 202. 快乐
    1.两数之和 已解答简单 相关标签相关企业 提示 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同......
  • 洛谷题单指南-排序-P1152 欢乐的跳
    原题链接:https://www.luogu.com.cn/problem/P1152题意解读:要判断相邻数差的绝对值是否覆盖1~n-1,只需遍历相邻两数之差,借助数组标记差的绝对值是否存在,然后遍历数组即可。解题思路:此题有两个注意点:1、数值要用longlong2、计算差值绝对值后,标记桶数组时,有可能导致越界,因为每个......
  • 寒假学习15
    今天接着学习声音转换训练: 点击脚本可以查看转换进度: http://localhost:6006/在转换声音数据的时候显示错误 问了问gpt:还是无法解决。......
  • day27 代码随想录算法训练营 39. 组合总和
    题目:39.组合总和我的感悟:还是没太理解这个index和i的区别感觉要继续听继续做剪枝要进行排序,这题,我先理解到不剪枝的版本就行 代码示例:classSolution:defcombinationSum(self,candidates:List[int],target:int)->List[List[int]]:res=[]......
  • 代码随想录 day34 K 次取反后最大化的数组和 加油站 分发糖果
    K次取反后最大化的数组和按照元素的绝对值大小进行排序把绝对值大的且小于0的取反如果还能取反那么奇数次的话就把绝对值小的取反偶数次不用管加油站首先如果总油量小于总消耗是一定不能跑完的这里的思路是如果[0,i]区间不能油量小于消耗那么就尝试从下一个i+1......
  • 洛谷P10115题解
    题意简述给定一个括号序列,求整个序列的美丽值最大。思维路径见到序列和权值,很容易想到需要用DP。我们定义\(f[i][j]\)表示第\(1\)到\(i\)个括号产生的美丽值最大值,其中\(j=0\)表示第\(i\)个括号本身不参与美丽值贡献,\(j=1\)表示第\(i\)个括号本身参与美丽值贡献......
  • P1561 [USACO12JAN] Mountain Climbing S
    P1561[USACO12JAN]MountainClimbingS贪心思路首先我们设\(c_i\)为第\(i\)头牛上山后又下山的时间。那么有两种情况,我们分类讨论。第\(i\)头牛上到山顶时,第\(i-1\)头牛还未下到山脚。第\(i-1\)头牛下山完毕但第\(i\)头牛还在上山。那么\(c_i\)的公式......
  • abc152F - Tree and Constraints
    abc152F-TreeandConstraints题意:给定一棵树,要求对每条边染成黑色或者白色,其中有m个限制,第i个限制形如ai,bi,表示ai到bi的路径上至少有一条黑色边,求方案数。看到数据第一反应是状压,但是好像没办法搞。于是考虑容斥,能想到容斥的话就差不多做完了,每次标记一下两个点和他们的lc......