LeetCode 454 四数相加2️⃣
思路
要找到满足条件的元组的个数,故使用哈希表,把个数作为值。 联想到两数之和,我们可以把四个数组分为两组,A和B,C和D。
- 元组个数记为count,初始为0.
- 对A和B进行两层循环遍历,把每两个元素和的值作为key,出现的次数作为value,得到AB元素之和的map。
- 再对C和D进行两层循环遍历,寻找元素和的相反数是否在map中。如果在,就把对应的value加到count上。
复杂度分析
- 时间复杂度:
- 空间复杂度:。在最坏情况下,各不相同,故需要存储个值
LeetCode 383 赎金信
思路
ransomNote由magazine中的字母组成,即ransomNote中的字母是否在magazine中存在足够的数量,存在👉哈希表。字母数量是固定的,所以可以使用数组作为哈希表,下标0~25代表键a~z,值记录magazine中字母的数量。
算法
- 遍历magazine的字母,把每个字母出现的次数记录在数组chars中
- 遍历ransomNote,把数组chars中字母对应的值-1
- 如果-1后值为负,返回false
- 返回true
复杂度分析
- 时间复杂度:
- 时间复杂度:
LeetCode 15 三数之和
思路
需要所有不相等的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)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
在这种思想之上,我们能很容易的在枚举过程中去重,但时间复杂度仍然是。 可以发现,当前两个元素固定时,第三个元素的值是固定的。而前两个指针只会从左到右移动,即a+b只会变大;故当(a,b,c)满足要求时,对于,满足的一定满足。故我们可以把第三个元素的指针改为与第二层for循环并列的从右到左移动,且当第三个指针与前两个指针相遇时,遍历就完成了。这样算法的复杂度被降为,即.
难点
在具体实现上,如何移动第三个指针k有很多细节:
- k>j:第三个指针必须在第二个指针右边。
- 当nums[k]<-(nums[i]+nums[j])时,就要停止移动k,进入下一个j。因为从当前再往左的数都不能满足条件了,需要寻找更大的nums[j]
LeetCode 18 四数之和
思路
乍一看和454 四数相加2️⃣有点像,但也是需要唯一的数值元组,用哈希去重很麻烦,故再次考虑双指针法。 考虑三数之和,本题很相似,只需要把从左到右的指针数量从二改成三,指针fourth的遍历应当和third是并列的,时间复杂度
易错点
力扣上有一个提交测试用例为
[1000000000,1000000000,1000000000,1000000000] -294967296
如果程序中都是用的是int整型,这个测试用例恰好会返回[1000000000,1000000000,1000000000,1000000000]
因为4*1000000000在整型中恰好会溢出为-294967296,可以说是非常刁钻。所以我们需要考虑到四个数加在一起导致的溢出。解决它只需要把计算和中的一个操作数强转为long型,再赋值给一个long型,最后再和target比较即可
哈希表总结
今日收获总结
今日学习时长4.5小时,前两道题目做的比较顺,后两道题因为要使用双指针法卡了一会儿。最后对哈希表的相关知识做了一个总结心得~