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

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

时间:2024-08-06 21:28:23浏览次数:12  
标签:四数 15 nums 代码 随想录 right 哈希 题目 left

力扣题部分:

454.四数相加II

题目链接:. - 力扣(LeetCode)  ​​​​​

思路(map哈希表):

        将数组分为两组分别用双重for循环遍历。第一组将来自不同数组的两个数之和(记为sum1)作为map的key,两个数之和出现的次数作为map的value,第二组通过在map查询来自不同数组的两个数之和(记为sum2)的相反数,确定是否存在sum1 = - sum2(也就是符合题意的sum1+sum2 = 0)如果找到了,将初值为0的计数器count += map[sum1],count加第一组map的value是因为这个sum2能和第一组中不同的sum1组合,有多少出现次数就能组合成多少不同组合。

代码实现:

383. 赎金信

题目链接:. - 力扣(LeetCode)

思路(数组哈希表):

        由于ransomNote和magazine只由小写字母组成,很容易想到数组哈希表,先将magazine存放进数组,记录各个字母出现频率,然后再读取ransomNote,读一个字母数组对应值减一,一旦ransomNote小于零,就说明ransomNote中的字母有比magazine多的,换句话说ransomNote不能由magazine里面的字符构成,return false。如果读完没有小于零的,说明符合题意,return true。

代码实现:        

15. 三数之和

题目链接:. - 力扣(LeetCode)

思路(哈希表):

        虽然可以用哈希表解决本题,但是不是很推荐(效率不高)

        这道题和上一道有很大不同的一点是去重。题目要求的是不能出现三个数值一模一样的数组(调换顺序也不行)有的人一开始就想着把符合条件的三元组放进vector中,然后再去重。然而这样是非常费时的,很容易超时,也是这道题目通过率如此之低的根源所在。由于去重的过程不好处理,有很多小细节,如果在面试中很难想到位。

        用哈希表的话很容易就能知道代码需要两层for循环,最后一个数用哈希表查找。但是由于不能采取先放进结果(result数组)里再对结果去重的方法,我们就需要排序用位置解决去重问题,在数据放进去之前就保证不重复,三个数的去重得分开进行,利用排序后一样值的位置是连续的这一特点,将经过相邻的值相同的元素在合适的时机continue保证结果不重复。所以要注意的去重细节是编写代码最困难的地方。然而即便如此,哈希表相比双指针法速度仍然略逊一筹。

(”合适的时机“在本题两个代码实现后面会有详细解释)

代码实现:

思路(双指针法):

        还是两层一样的for循环,不同的是第二层的指针left要和第三个指针right进行不一样的移动操作:通过nums[left] + nums[right] 与 0 - nums[i] 对比,前者大了的话 right--就往里走使值变小,小了的话就让left++使值变大,两个操作不断将值逼近达到 a + b + c = 0 (也就是nums[left] + nums[right] + nums[i]) = 0。当然我们仍然需要在合适的时机continue保证结果不重复。

 代码实现:

 关于“合适的时机”

        理解这个其实才是对整个题目代码是否ac的关键,涉及到去重的逻辑思考。

        说到去重,其实主要考虑三个数的去重。a, b ,c, 对应的就是 nums[i],nums[left],nums[right](哈希表思路同理)。对于a来说 去重的操作是if(i > 0 && nums[i] == nums[i - 1])

        下面思考一下这个问题: 把原操作换成 if(nums[i] == nums[i + 1])行不行呢?

        答案是不行,就比如遍历[-1,-1,2]时,换掉的操作会直接continue 错过这个正确答案。

        这体现了我们的一个去重的原则:

        我们要做的是 不能有重复的三元组,但三元组内的元素是可以重复的!

        对b,c去重的双指针法中还有一个要注意的点:

         如果把双指针法的代码中第18 - 20行换成如下格式,是否有必要呢?

while (right > left) {
    if (nums[i] + nums[left] + nums[right] > 0) {
        right--;
        // 去重 right
        while (left < right && nums[right] == nums[right + 1]) right--;
    } else if (nums[i] + nums[left] + nums[right] < 0) {
        left++;
        // 去重 left
        while (left < right && nums[left] == nums[left - 1]) left++;
    } else {
    }
}

        答案是否定的,这种去重其实对提升程序运行效率没有帮助。

        拿right去重为例,即使不加这个去重逻辑,依然根据 while (right > left) 和 if (nums[i] + nums[left] + nums[right] > 0) 去完成right-- 的操作。

        多加了 while (left < right && nums[right] == nums[right + 1]) right--; 这一行代码,其实就是把 需要执行的逻辑提前执行了,但并没有减少 判断的逻辑。

        最直白的思考过程,就是right还是一个数一个数的减下去的,所以在哪里减的都是一样的。

        所以这种去重 是可以不加的。 仅仅是 把去重的逻辑提前了而已。

18. 四数之和

题目链接:. - 力扣(LeetCode)

思路(双指针法):

基本和三数之和差不多,就是向外套一层for循环,但是题目有一些变化导致需要注意更多的点。

比如target 不是 0 导致如果target 是负数,nums[k] > target 就不能是直接返回的条件了,例如[-4,-3,-2,-1],target = -10。如果照搬就直接返回错过正确答案了。所以要在原来的基础上加条件, 变成 if(nums[k] > target && (nums[i] >=0 || target >=0)) 才能达到剪枝的效果。

代码实现:

总结:

        通过这两天对哈希表的学习,我掌握了哈希表的使用方法和依据题目使用哪一种哈希表结构的挑选思路,我可以明显的感受到今天的题目难度比之前的难得多,需要思考的细节也有很多。当然,题目难度的上升能使我接触更多的解决方法,学会挑选方法思考方法优劣可以说是我学这哈希表这一章最大的收获了。
 

标签:四数,15,nums,代码,随想录,right,哈希,题目,left
From: https://blog.csdn.net/b1ankwall/article/details/140953628

相关文章

  • [Tkey] CF1526B I Hate 1111
    给定一个数,将它表示成若干个形如\(11,111,1111\cdots\)之类的数之和,判断有没有可行解考虑到一种贪心,即从高位开始依次向下减去每位数字,判断还能不能减动,减不动或者没减完就报告无解.显然这样的贪心仅在\(11,111,1111\cdots\)的出现次数之和不超过\(9\)时是稳定正确的,一......
  • 代码随想录算法训练营第59天 | 最小生成树
    53.寻宝https://kamacoder.com/problempage.php?pid=1053prim算法精讲https://www.programmercarl.com/kamacoder/0053.寻宝-prim.htmlkruskal算法精讲https://www.programmercarl.com/kamacoder/0053.寻宝-Kruskal.html题目描述在世界的某个区域,有一些分散的神秘岛屿,每......
  • SSM高校就业管理系统157v3 系统界面在最后面
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表系统内容:学生,招聘信息,学生应聘,企业,班级,教师开题报告内容一、研究背景与意义随着高校招生规模的不断扩大,毕业生就业问题日益突出。传统招聘方式已难以满足......
  • 代码随想录Day7
    454.四数相加Ⅱ给你四个整数数组nums1、nums2、nums3和nums4,数组长度都是n,请你计算有多少个元组(i,j,k,l)能满足:0<=i,j,k,l<nnums1[i]+nums2[j]+nums3[k]+nums4[l]==0示例1:输入:nums1=[1,2],nums2=[-2,-1],nums3=[-1,2],nums4=[0,2]输......
  • 代码随想录Day6
    454.四数相加Ⅱ给你四个整数数组nums1、nums2、nums3和nums4,数组长度都是n,请你计算有多少个元组(i,j,k,l)能满足:0<=i,j,k,l<nnums1[i]+nums2[j]+nums3[k]+nums4[l]==0示例1:输入:nums1=[1,2],nums2=[-2,-1],nums3=[-1,2],nums4=[0,2]输......
  • ARC152C 题解
    blog。可能是很简单的,但是我实在是不会这种神秘题/ll/ll。Conclusion1.记\(d=a_n-a_1\),则极差始终等于\(d\)。证明显然。Conclusion2.操作极值时,最小值始终变化为\(d\),并且可以进行无限次这样的变化。证明显然。题意转变:最小化\((\texttt{最小值}\bmodd)\),且最小......
  • Navicat Premium15下载破解教程
    一、激活前的准备下载软件安装包网盘地址:https://pan.quark.cn/s/8651c02c7191密码:Es8Y2.环境准备断网关闭“病毒和威胁防护”设置中的“实时保护”二、安装navicatpremium,按步骤进行即可。注意:安装成功后,不要打开软件。在后面步骤才能打开。(一不小心......
  • 「代码随想录算法训练营」第三十天 | 动态规划 part3
    46.携带研究材料(0-1背包问题)题目链接:https://kamacoder.com/problempage.php?pid=1046文章讲解:https://programmercarl.com/背包理论基础01背包-1.html视频讲解:https://www.bilibili.com/video/BV1cg411g7Y6/题目状态:看题解过思路:创建一个二维的dp数组,用来进行动态规划,其......
  • 鸿蒙UI系统组件15——画布(Canvas)
    如果你也对鸿蒙开发感兴趣,加入“Harmony自习室”吧!扫描下方名片,关注公众号,公众号更新更快,同时也有更多学习资料和技术讨论群。⭐️ 概 述      前一章我们学习了Shape绘制来绘制自定义形状,在实际的业务开发中,有可能我们需要绘制更复杂的图形,例如统计图中的饼图、......
  • 代码随想录二刷栈与队列
    代码随想录二刷栈与队列栈模拟队列具体思路如下:程序如下:classMyQueue:def__init__(self):self.stack_in=[]self.stack_out=[]defpush(self,x:int)->None:self.stack_in.append(x)defpop(self)->int:if......