算法训练Day7| LeetCode454. 四数相加II(Map作哈希表);383.赎金信(数组作哈希表);15.三数之和(双指针);18.四数之和(双指针)

目录

LeetCode454. 四数相加

1. 思路

2. 代码实现

3. 复杂度分析

4. 思考

 Leetcode383. 赎金信 

1. 思路

2. 代码实现

3. 复杂度分析

4. 思考

Leetcode15. 三数之和

方法一:双指针法

1. 思路

 2. 代码实现

3. 复杂度分析

4. 思考

Leetcode18. 四数之和 

1. 思路

2. 代码实现

3. 复杂度分析

4. 思考


LeetCode454. 四数相加

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

1. 思路

本题的暴力法是4个for loop循环,时间复杂度为O(N^4),不再赘述。

这道题目的一个很重要的点是不用考虑去重,例如A B C D 中的所有元素都为0的时候,就算找到的元组都是[ 0, 0, 0, 0 ]这种形式,但是他们仍然属于不同的元组,因为其中的0来自于数组中不同的位置。这大大简化了这道题的思路。

怎么想到用哈希法?

思考:在集合中判断一个元素是否出现过的时候,想到要用哈希法。

可以先遍历数组A和数组B,储存所有可能性在哈希表中,然后一一遍历数组C和数组D的组合;看0-(C+D)元素是否在哈希表中出现,如果出现,就找到了合适的元组,这里涉及到了在哈希表中判断元素是否出现过,所以想到用哈希法。

用哈希法的哪种数据结构?

数值大小不可控,不可以用array;题意要统计元组出现的次数,所以我们需要有key-value的键值对, 所以说用Map。

Map用来干啥?其中的Key-value分别是啥?

Map用来存AB数组元素相加的所有可能性,key为相加之和的数值,value为这个数值出现的次数。

具体执行思路

  1. 首先定义 一个map,key放a和b两数之和,value 放a和b两数之和出现的次数;
  2. 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中;
  3. 定义int变量count,用来统计 a+b+c+d = 0 出现的次数;
  4. 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来;
  5. 最后返回统计值 count 就可以了。

2. 代码实现

# Map作哈希表
# time:O(n^2); space:O(n^2)
class Solution(object):
    def fourSumCount(self, nums1, nums2, nums3, nums4):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :type nums3: List[int]
        :type nums4: List[int]
        :rtype: int
        """
        record = {}
        count = 0
        for i in nums1:
            for j in nums2:
                Sum = i+j
                if Sum in record:
                    record[Sum] += 1
                else:
                    record[Sum] = 1
        for k in nums3:
            for l in nums4:
                target = 0-k-l 
                if target in record:
                    count += record[target]
        return count

3. 复杂度分析

时间复杂度:O(n^2)

我们使用了两次二重循环,时间复杂度均为 O(n^2);在循环中对哈希映射进行的修改以及查询操作的期望时间复杂度均为 O(1),因此总时间复杂度为 O(n^2);

空间复杂度:O(n^2)

即为哈希映射需要使用的空间。在最坏的情况下,A[i]+B[j]的值均不相同,因此值的个数为 n^2 ,也就需要 O(n^2) 的空间。

4. 思考

  1. 提出疑问,为什么不只遍历A,得到Map,然后再遍历B,C,D中所有组合的可能性?因为这样的话,时间复杂度和空间复杂度就提升为O(N^3);
  2. 注意count计数器在加的时候,并不是直觉上的count+= 1,因为出现的频率不一定是1,比如说map中储存的是5:3,对应三组AB元组,分别是,A[1] +B[2] = 5,A[2] +B[3] = 5,A[3] +B[4] = 5,然后在C+D中找到了一对相加等于-5的,所以说这样就找到了三组四元组,应该count+3;
  3. 和其他题目的比较思考:这道题和两数之和思路非常一致,只是创建Map和查找Map的时候,都变成了两个for loop一起遍历,value存的是下标;和有效字母的异位词处理也很类似,只是根据不同情况用到的元素不同,都是先创建容器,再利用容器找我们需要的结果;
  4. 题目乍眼看和三数之和,四数之和差不多,其实差很多;本题是使用哈希法的经典题目,而以上两道题不适合使用哈希法,因为三数之和和四数之和这两道题目使用哈希法在不超时的情况下做到对结果去重是很困难的,很有多细节需要处理。而这道题目是四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑有重复的四个元素相加等于0的情况,所以相对于题目18. 四数之和,题目15.三数之和,还是简单了不少!

Reference

1. 力扣

2.  代码随想录

本题学习时间:60分钟。


 Leetcode383. 赎金信 

链接:

你可能感兴趣的:(代码随想录训练营,算法,散列表,leetcode)