在问 · 算法题解

349. 两个数组的交集

简单二分查找排序 + 二分查找力扣原题 ↗

题目描述

输入两个整数数组 nums1 和 nums2。

找出同时在两个数组中出现过的所有数值,组成数组返回。每个数值在结果里只放一次,即使它在原数组里重复出现。

结果的顺序不限。

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

解释:两个数组都含有 2,结果中只保留一个。

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

解释:共同出现的数是 4 和 9,写成 [9,4] 也正确。

数据范围

  • 1 <= nums1.length, nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 1000

解题思路:排序 + 二分查找

把 nums2 排序后就可以在它上二分查找。nums1 也排序,这样相同的数挨在一起,重复的直接跳过,结果自然去重。对 nums1 中每个不同的 x,用 bisect_left 在 nums2 中找第一个 >= x 的位置 j,若 nums2[j] == x 就说明 x 在 nums2 里。

为什么正确

res 中是 nums1 已处理部分里、也在 nums2 中出现的不同数字,且按升序排列。

复杂度分析

时间 O(m log m + n log n),空间 O(1)(不计返回值和排序栈)。

易错点

bisect_left 返回的 j 可能等于 len(nums2)(x 比所有数都大),先判断 j < len(nums2) 再访问 nums2[j]。nums1 中的重复数要跳过,否则结果会重复。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        nums1.sort()
        nums2.sort()
        res = []
        for i, x in enumerate(nums1):
            if i > 0 and x == nums1[i - 1]:
                continue
            j = bisect_left(nums2, x)
            if j < len(nums2) and nums2[j] == x:
                res.append(x)
        return res

载入编辑器,自己跑一遍 →

其他解法

哈希集合用 O(m + n) 空间换来线性时间;排序做法只用排序栈空间,结果自然有序,适合输入已经有序的场景。

解法 2:两个哈希集合 时间 O(m + n),空间 O(m + n)

把 nums1 的元素放进哈希集合。遍历 nums2,如果元素在集合中就加入答案,并把它从集合中删掉,这样重复的值只会被记录一次。

线性时间,不需要排序,也不改动输入数组。需要额外的哈希表空间,输出顺序不保证有序。

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        seen = set(nums1)
        res = []
        for x in nums2:
            if x in seen:
                res.append(x)
                seen.remove(x)
        return res

二分查找 专题的其他题目

查看 二分查找 全部题目 →