代码编织梦想

今日题目:

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

解题思想:

  1. 数组分组,巧用哈希表

454题四数相加,哈希表的经典题目,因为需要判断某个元素是否在表中出现过,所以自然想到哈希表。这道题有个很关键的地方,答案无需去重,因为相同数字放在数组不同位置,它们也是不同的。4个数组,两两一组,先遍历nums1和nums2,在map中记录它们的答案和出现次数,再遍历nums3和nums4,寻找它们的和的负数是否在map中出现。
注意,当在map寻找到对应的值时,并不是直接简单count++,因为答案无需去重,所以应该加的是对应值对应的value
比较巧妙的地方是数组两两分组,这样可以有效降低时间复杂度。

  1. 双指针法

15题三数之和难点是在去重上,用哈希表的话在去重上比较困难,所以这里选择双指针。
首先对数组进行排序,排序之后使用一轮for循环,先确定第一个数,再这个数后面的区间中利用双指针寻找符合条件的答案。
三个位置的指针都需要去重处理。我们需要求的是不能重复的三元组,但三元组里面的元素是可以重复的
对i的去重逻辑,是让它与前一个位置对比,看是否相同。对L和R指针的去重逻辑,一定要先收获一个结果再去判断下一个值是否重复,比如数组[0,0,0,0,0],如果先去重处理再收获结果,那么L和R指针直到相遇也没有收获一个结果。

  1. 去重与剪枝

四数之和,思路大体和三数之和相似,比它多套一层循环。但是本题求的target不是固定的数,它可能为负数,所以剪枝的时候不能直接if(nums[i]>target) break
四个指针都需要进行对应的去重处理,i>0 && nums[i]==nums[i-1]j>i+1 && nums[j]==nums[j-1]注意这里是j>i+i,因为j的初始位置是设置为i+1,自己在做的时候犯了一个小错,把条件设置为了j>i

代码:

  • 454.四数相加
var fourSumCount = function(nums1, nums2, nums3, nums4) {
    const map = new Map()
    let count = 0

    for(const n1 of nums1) {
        for(const n2 of nums2) {
            const sum = n1+n2
            map.set(sum, (map.get(sum)||0) + 1)
        }
    }

    for(const n3 of nums3) {
        for(const n4 of nums4) {
            const sum = n3+n4
            count +=(map.get(-sum) || 0)
        }
    }

    return count
};
  • 383.赎金信
var canConstruct = function(ransomNote, magazine) {
    const map = new Map()
    for(const letter of magazine) {
        map.set(letter, (map.get(letter)||0)+1 )
    }

    for(const letter of ransomNote) {
        if(!map.get(letter) ||map.get(letter)<0) return false
        map.set(letter, (map.get(letter)||0)-1 )
    }

    return true
};
    1. 三数之和
var threeSum = function(nums) {
    nums.sort((a,b) => a-b)
    const res = []
    
    for(let i =0; i<nums.length; i++) {
        if(nums[i]>0) return res
        if(i>0 && nums[i] == nums[i-1]) continue  //对i去重

        let L = i+1
        let R = nums.length-1

        while(L<R) {
            let sum = nums[i] + nums[L] + nums[R]
            if(sum ==0 ) {
                res.push([nums[i], nums[L], nums[R]])

                while(nums[L] == nums[L+1] && L<R) L++  //对L去重
                while(nums[R] == nums[R-1] && L<R) R--	//对R去重
                L++
                R--
            }
            if(sum>0){
                R--
            }
            if(sum <0){
                L++
            }
        }

    }

    return res
};
    1. 四数之和
var fourSum = function(nums, target) {
    nums.sort((a,b) => a-b)
    const res = []
    for(let i=0; i<nums.length-3; i++) {
        if(nums[i]>target && target>0) break  //一级剪枝
        if(i>0 && nums[i]== nums[i-1]) continue //对i去重处理
        
        for(let j=i+1; j<nums.length-2; j++) {
            let twoSum = nums[i]+nums[j]
            if(twoSum>target && target>0) break  //二级剪枝
            if(j>i+1 && nums[j] == nums[j-1]) continue  //对j去重处理

            let L = j+1
            let R = nums.length-1


            while(L<R){
                let fourSum = twoSum+nums[L]+nums[R]
                if(fourSum == target) {
                    res.push([nums[i], nums[j], nums[L], nums[R]])
                    while(L<R && nums[L] == nums[L+1]) L++
                    while(L<R && nums[R] == nums[R-1]) R--
                    L++
                    R--
                }
                if(fourSum>target) R--
                if(fourSum<target) L++
            }

        }
    }

    return res
};

总结:

不难发现三数之和和四数之和的做法都是有固定模式的,先固定一个或两个指针,再在剩余区间内用左右两指针不断探测符合条件的结果集,并且对每个指针都需要去重处理。但是去重的地方一定要想清楚,到底是与前面的指针相判断、还是后面的指针相判断、是先收获结果再去重还是先去重再收获结果。为了提高算法效率,还可以进行适当剪枝操作。
自己在做四数之和的时候,思路是对的,但是忽略了target值可能为负数的情况,剪枝错误导致一些用例不通过,说明自己对题目的细节把控还是不太到位。今天的题目还是需要多次练习巩固。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/FloriaLiii/article/details/127380963

383.赎金信_张荣华_csdn的博客-爱代码爱编程

给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成。如果可以构成,返回 true ;否则返回 false。 (题目说明:为了不暴露赎金信字迹,要从杂志上搜索各个需要的字母,组成单词来表达意思。) 注意: 你可以假设两个字符串均只含有小写字母。

leetcode:383.赎金信-爱代码爱编程

题目 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/ransom-note 为了不在赎金信中暴露字迹,从杂志上搜索各个需要的字母,组成单词来表达意思。 给你一个赎金信 (ransomNote) 字符串和一个杂志(magazine)字符串,判断 ransomNote 能不能由 magazines

力扣:383.赎金信-爱代码爱编程

力扣:383.赎金信题目: 给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以,返回 true ;否则返回 false 。 magazine 中的每个字符只能在 ransomNote 中使用一次。 代码跟上一章几乎是一样的: class Solution {

leetcode-383.赎金信_改个名字显得不这么嚣张的博客-爱代码爱编程

leetcode-383.赎金信 题目解题思路思路一 遍历查找思路二 统计对比思路三 统计对比--二维数组版思路四 统计对比--优化版其他思路 总结 题目 给你两个字符串:ransomNote 和 mag

力扣算法:454.四数相加|| 383.赎金信 15.三数之和 18.四数之和_菜菜要要努力的博客-爱代码爱编程

学习内容 力扣算法: 454.四数相加|| 383.赎金信 15.三数之和 18.四数之和 具体内容 454.四数相加|| 给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是

代码随想录算法训练营第七天|454.四数相加Ⅱ、383.赎金信、15.三数之和、18.四数之和_chauncey1995的博客-爱代码爱编程

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

代码随想录算法训练6day| 454.四数相加ii 、 383.赎金信、15. 三数之和 、18. 四数之和、1. 两数之和 。_竹枝词、的博客-爱代码爱编程

前言:只做了四数相加II 四数相加II  主要思路:我们需要判断的是四个数组中的和为零的情况,对位置并没有要求,所以想到了哈希算法         1、哈希算法主要来判断在集合中一个元素是否出现         2、此时数据太过于庞大,需要考虑Map,其中Map用来存AB数组元素相加的所有情况,而key为相加的数值,value为这个值出现的次数。

训练营0927|哈希表系列(四数相加|赎金信|三数之和|四数之和)_chrison_mu的博客-爱代码爱编程

  目录  *454.四数相加II 383.赎金信 15.三数之和 *18.四数之和 *454.四数相加II  四个数组里面寻找四个数相加和为0.巧妙的去利用hashmap判断是否存在的功能,hashmap1里面放前两个数组的和,以及这个和出现的次数 hashmap2里面放后两个数组的和(或者和的相反数)----->判断是否存在于h

2022sdut知到/智慧树----c语言第六章测试题解_数据2201qjy的博客-爱代码爱编程

** 第六章测试 ** 1【判断题】 (10分) 有下列程序段,程序段运行后的输出结果##2##3##4##5( )。 int k; for (k=2;k<6;k++,k++) printf(“##%d”

ch3_6四数相加 && ch3_7赎金信-爱代码爱编程

1. 四数相加 lc454 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。 为了使问题简单化,所

力扣 383.赎金信-爱代码爱编程

给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以,返回 true ;否则返回 false 。 magazine 中的每个字符只能在 ransomNote 中使用一次。 来源:力扣(LeetCode)   class Solution { pu

代码随想录算法训练营第六天 242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和-爱代码爱编程

目录 一、242.有效的字母异位词 二、349. 两个数组的交集 三、202. 快乐数 四、1. 两数之和 五、总结 一、242.有效的字母异位词 题目链接:242. 有效的字母异位词 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和

力扣练习第七天 :454.四数相加||、383.赎金信、15.三数之和、18.四数之和-爱代码爱编程

454.四数相加||   哈哈,开心,用c语言自己做出来了。美的飞起。首先,看了卡哥的提示,要用map解题。key用来存储nums1[i]+nums2[j的和, value用来存储出现的次数。另外 ,还有个小小的问题, 就是if(s)(光标所在处)中重新分配一次,就会报错,这是为什么呢?是重新弄了一块内存吗?但是现在找到的不是指针吗???这是一个小疑

代码随想录算法训练营第六天/454.四数相加2、383.赎金信、15.三数之和、18.四数之和-爱代码爱编程

目录 今日内容: 454.四数相加2 383.赎金信 15.三数之和 18.四数之和 454.四数相加2 题目链接:https://leetcode.cn/problems/4sum-ii/submissions/ 第一想法:之前有做“二数之和”,想着应该都有相通之处,都是不知道该如何进行处理。 学习代码随想录后:和“二数之和”总体是

07-爱代码爱编程

文章目录 454.四数相加II383.赎金信15.三数之和18.四数之和 454.四数相加II 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l)

算法训练day7| leetcode454. 四数相加ii(map作哈希表);383.赎金信(数组作哈希表);15.三数之和(双指针);18.四数之和(双指针)-爱代码爱编程

目录 LeetCode454. 四数相加 1. 思路 2. 代码实现 3. 复杂度分析 4. 思考  Leetcode383. 赎金信  1. 思路 2. 代码实现 3. 复杂度分析 4. 思考 Leetcode15. 三数之和 方法一:双指针法 1. 思路  2. 代码实现 3. 复杂度分析 4. 思考 Leetcode

代码随想录刷题思路与心得06|454. 383. 15. 18._代码随想录怎么刷题java-爱代码爱编程

454.四数相加Ⅱ         本题希望求四个相加为0的全部组合,但是这个题目和四数之和是不一样的,这个给了四个不同的list,并且他们长度相同。这就使得题目变得更简单了。直接看四数之和可能有些无从下手,但是如果题目只有nums1,nums2两个list,大家肯定都会做,就是遍历一下nums1,看看0-nums1里面的数是不是在nums2里面。那

代码随想录训练营day7:454四数相加ii、383赎金信、15三数之和、18、四数之和-爱代码爱编程

1.四数相加II:代码随想录 (programmercarl.com)         1、此题相对于四数相加会更加简单,因为本题不需要去重,而四数之和需要去重。         2、因为int的范围太大了,所以此题不能用数组,要考虑用set或者map         3、因为不仅要考虑数值是否出现,还要考虑出现的次数,故要使用map    

洛谷 p7802 [coci2015-爱代码爱编程

PS:如果读过题了可以跳过题目描述直接到题解部分 提交链接:洛谷 P7802 [COCI2015-2016#6] SAN 题目 题目描述