LeetCode349. 两个数组的交集 + 350. 两个数组的交集 II

349. 两个数组的交集

1.1题目描述

https://leetcode-cn.com/problems/intersection-of-two-arrays

给定两个数组,编写一个函数来计算它们的交集。

输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2]

输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [9,4]

  • 输出结果中的每个元素一定是唯一的
  • 我们可以不考虑输出结果的顺序。

1.2代码详解

1)使用set集合

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        set1 = set(nums1)
        set2 = set(nums2)
        
        if len(set1) < len(set2):
            return self.set_insert(set1,set2)
        else:
            return self.set_insert(set2,set1)
    
    def set_insert(self, set1, set2):
        return [x for x in set1 if x in set2]
  • 时间复杂度:O(m+n),其中 n 和 m 是数组的长度。将 nums1 转换为集合需要 O(n)的时间,类似地,将 nums2 转换为集合需要 O(m) 的时间。而在平均情况下,集合的 in/contains 操作只需要 O(1)的时间。
  • 空间复杂度:O(m+n),最坏的情况是数组中的所有元素都不同。

2)内置函数

class Solution:
    def intersection(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: List[int]
        """  
        set1 = set(nums1)
        set2 = set(nums2)
        return list(set2 & set1)

3)双指针+排序

其实就是把两个数组进行排序,然后用双指针进行滑动对比就可以了。

  • 先将nums1 与nums2 排序,然后游走两个指针,情况都写出来了,没有用else
  • 时间复杂度:O(nlogn)

4)二分法 +排序

把一个短的数组如nums1进行排序,然后nums2中的每一个元素在nums1中进行二分查找。

将nums2排序,然后查找nums1的元素,需要准备一个binarySearch的辅助方法,注意left <= right

https://leetcode-cn.com/problems/intersection-of-two-arrays/solution/duo-chong-jie-fa-jie-jue-349-liang-ge-shu-zu-de-ji/

350. 两个数组的交集 II

2.1题目描述

https://leetcode-cn.com/problems/intersection-of-two-arrays-ii/

给定两个数组,编写一个函数来计算它们的交集。

输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2,2]

输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [4,9]

输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。(不同之处!!!)

我们可以不考虑输出结果的顺序。

进阶:

  1. 如果给定的数组已经排好序呢?你将如何优化你的算法?
  2. 如果 nums1 的大小比 nums2 小很多,哪种方法更优?
  3. 如果 nums2 的元素存储在磁盘上,磁盘内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?

2.2代码详解

1)法一:排序双指针(适用于进阶1)

如果给定的数组已经排好序呢?你将如何优化你的算法?

将两个数组进行排序,随后用双指针顺序查找相同的元素

  • 时间复杂度O(max(nlogn, mlogm, n+m))
  • 空间复杂度O(1) (n,m分别为两个数组的长度)

进阶问题一中已排序的数组,则只需O(n)的时间复杂度

class Solution:
    def intersect(self, nums1, nums2):
        nums1.sort()
        nums2.sort()
        res = []
        left, right = 0, 0
        while left < len(nums1) and right < len(nums2):
            if nums1[left] < nums2[right]:
                left += 1
            elif nums1[left] == nums2[right]:
                res.append(nums1[left])
                left += 1
                right += 1    
            else:
                right += 1
        return res

2)法二:哈希计数 将较小的数组哈希计数(适用于进阶问题2)

如果 nums1 的大小比 nums2 小很多,哪种方法更优?

随后在另一个数组中根据哈希来寻找。 时间复杂度O(max(n, m)) 空间复杂度O(min(n, m))  

dict.get(key, default=None)根据key查找value,如果指定键的值不存在时,返回该默认值

class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
        counts = {} # key:元素 ,value:出现频次
        res = []

        for num in nums1:
            counts[num] = counts.get(num, 0) + 1 # 记录nums1 中每个数出现的频次
        # 遍历nums2
        for num in nums2:
            # counts[num] > 0 表示nums2 中有nums1 相同的元素
            if num in counts and counts[num] > 0:
                res.append(num)
                counts[num] -= 1 # 查找到对应后的元素失效

        return res

错误案例:

原因:如测试用例中的 [5] ,字典中没有这个值

3)法三:通过归并外排将两个数组排序后再使用排序双指针查找

如果 nums2 的元素存储在磁盘上,磁盘内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?

对应进阶问题三,如果内存十分小,不足以将数组全部载入内存,那么必然也不能使用哈希这类费空间的算法,只能选用空间复杂度最小的算法,即解法一。

 但是解法一中需要改造,一般说排序算法都是针对于内部排序,一旦涉及到跟磁盘打交道(外部排序),则需要特殊的考虑。归并排序是天然适合外部排序的算法,可以将分割后的子数组写到单个文件中,归并时将小文件合并为更大的文件。当两个数组均排序完成生成两个大文件后,即可使用双指针遍历两个文件,如此可以使空间复杂度最低。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值