代码随想录算法训练营Day07|454 四数相加2️⃣,383 赎金信,15 三数之和,18 四数之和

89 阅读5分钟

LeetCode 454 四数相加2️⃣

题目链接:leetcode.cn/problems/4s…

文档讲解:programmercarl.com/0454.四数相加II…

视频讲解:www.bilibili.com/video/BV1Md…

思路

要找到满足条件的元组的个数,故使用哈希表,把个数作为值。 联想到两数之和,我们可以把四个数组分为两组,A和B,C和D。

  1. 元组个数记为count,初始为0.
  2. 对A和B进行两层循环遍历,把每两个元素和的值作为key,出现的次数作为value,得到AB元素之和的map。
  3. 再对C和D进行两层循环遍历,寻找元素和的相反数是否在map中。如果在,就把对应的value加到count上。

复杂度分析

  • 时间复杂度:O(n2)O(n^2)
  • 空间复杂度:O(n2)O(n^2)。在最坏情况下,A[i]+B[j]A[i]+B[j]各不相同,故需要存储n2n^2个值

LeetCode 383 赎金信

题目链接:leetcode.cn/problems/ra…

文档讲解:programmercarl.com/0383.赎金信.ht…

思路

ransomNote由magazine中的字母组成,即ransomNote中的字母是否在magazine中存在足够的数量,存在👉哈希表。字母数量是固定的,所以可以使用数组作为哈希表,下标0~25代表键a~z,值记录magazine中字母的数量。

算法

  1. 遍历magazine的字母,把每个字母出现的次数记录在数组chars中
  2. 遍历ransomNote,把数组chars中字母对应的值-1
    1. 如果-1后值为负,返回false
  3. 返回true

复杂度分析

  • 时间复杂度:O(n)O(n)
  • 时间复杂度:O(1)O(1)

LeetCode 15 三数之和

题目链接:leetcode.cn/problems/3s…

文档讲解:programmercarl.com/0015.三数之和.h…

视频讲解:www.bilibili.com/video/BV1GW…

思路

需要所有不相等的i, j, k对应的三元组。即对于任意nums[i],nums[j],寻找是否存在nums[k]使三者和为0。

涉及存在的题目,第一反应就是哈希法。但考虑时间开销,首先要两层for循环遍历数组,找出所有组合;接着需要把nums[k]和对应的组合配对;最后还需要对整个组合列表去重。可以感觉到复杂度很高,那有没有简便一些的方法?

双指针法

「不重复」的本质是什么?

我们保持三重循环的大框架不变,只需要保证:

  • 第二重循环枚举到的元素不小于当前第一重循环枚举到的元素;
  • 第三重循环枚举到的元素不小于当前第二重循环枚举到的元素。 也就是说,我们枚举的三元组 (a,b,c) 满足 a≤b≤c,保证了只有 (a,b,c) 这个顺序会被枚举到,而 (b,a,c)、(c,b,a) 等等这些不会,这样就减少了重复。要实现这一点,我们可以将数组中的元素从小到大进行排序,随后使用普通的三重循环就可以满足上面的要求。 同时,对于每一重循环而言,相邻两次枚举的元素不能相同,否则也会造成重复。

作者:力扣官方题解

链接:leetcode.cn/problems/3s…

来源:力扣(LeetCode)

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

在这种思想之上,我们能很容易的在枚举过程中去重,但时间复杂度仍然是O(n3)O(n^3)。 可以发现,当前两个元素固定时,第三个元素的值是固定的。而前两个指针只会从左到右移动,即a+b只会变大;故当(a,b,c)满足要求时,对于a>a,b>ba'>a,b'>b,满足a+b+c=0a'+b'+c'=0cc'一定满足c<cc'<c。故我们可以把第三个元素的指针改为与第二层for循环并列从右到左移动,且当第三个指针与前两个指针相遇时,遍历就完成了。这样算法的复杂度被降为O(n2)+O(n)O(n^2)+O(n),即O(n2)O(n^2).

难点

在具体实现上,如何移动第三个指针k有很多细节:

  1. k>j:第三个指针必须在第二个指针右边。
  2. 当nums[k]<-(nums[i]+nums[j])时,就要停止移动k,进入下一个j。因为从当前再往左的数都不能满足条件了,需要寻找更大的nums[j]

LeetCode 18 四数之和

题目链接:leetcode.cn/problems/4s…

文档讲解:programmercarl.com/0018.四数之和.h…

视频讲解:www.bilibili.com/video/BV1DS…

思路

乍一看和454 四数相加2️⃣有点像,但也是需要唯一的数值元组,用哈希去重很麻烦,故再次考虑双指针法。 考虑三数之和,本题很相似,只需要把从左到右的指针数量从二改成三,指针fourth的遍历应当和third是并列的,时间复杂度O(n3)O(n^3)

易错点

力扣上有一个提交测试用例为 [1000000000,1000000000,1000000000,1000000000] -294967296 如果程序中都是用的是int整型,这个测试用例恰好会返回[1000000000,1000000000,1000000000,1000000000] 因为4*1000000000在整型中恰好会溢出为-294967296,可以说是非常刁钻。所以我们需要考虑到四个数加在一起导致的溢出。解决它只需要把计算和中的一个操作数强转为long型,再赋值给一个long型,最后再和target比较即可

哈希表总结

哈希表算法总结.png

今日收获总结

今日学习时长4.5小时,前两道题目做的比较顺,后两道题因为要使用双指针法卡了一会儿。最后对哈希表的相关知识做了一个总结心得~