我正在参加「启航计划」

标题

给你两个整数数组nums1nums2,请你以数组形式返回两数组的交集。返回成果中每个元素呈现的次数,应与元素在两个数组中都呈现的次数共同(如果呈现次数不共同,则考虑取较小值)。能够不考虑输出成果的顺序。

示例 1:

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

示例 2:

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

办法一:哈希表

思路及解法

因为同一个数字在两个数组中都或许呈现屡次,因而需求用哈希表存储每个数字呈现的次数。对于一个数字,其在交集中呈现的次数等于该数字在两个数组中呈现次数的最小值。

首要遍历第一个数组,并在哈希表中记录第一个数组中的每个数字以及对应呈现的次数,然后遍历第二个数组,对于第二个数组中的每个数字,如果在哈希表中存在这个数字,则将该数字添加到答案,并减少哈希表中该数字呈现的次数。

为了降低空间复杂度,首要遍历较短的数组并在哈希表中记录每个数字以及对应呈现的次数,然后遍历较长的数组得到交集。

代码

class Solution {
    func intersect(_ nums1: [Int], _ nums2: [Int]) -> [Int] {
        if nums1.count > nums2.count {
            return intersect(nums2, nums1)
        }
        var map: [Int : Int] = [:]
        for num in nums1 {
            let count: Int = (map[num] ?? 0) + 1
            map[num] = count
        }
        var intersection: [Int] = []
        for num in nums2 {
            let count: Int = map[num] ?? 0
            if count > 0 {
                intersection.append(num)
                map[num] = count - 1
            }
        }
        return intersection
    }
}

复杂度剖析

  • 时刻复杂度:O(m+n)O(m+n),其间 mmnn 分别是两个数组的长度。需求遍历两个数组并对哈希表进行操作,哈希表操作的时刻复杂度是 O(1)O(1),因而总时刻复杂度与两个数组的长度和呈线性关系。

  • 空间复杂度:O(min(m,n))O(min(m,n)),其间 mmnn 分别是两个数组的长度。对较短的数组进行哈希表的操作,哈希表的大小不会超越较短的数组的长度。为返回值创立一个数组 intersectionintersection,其长度为较短的数组的长度。

办法二:排序 + 双指针

思路及解法

如果两个数组是有序的,则能够运用双指针的办法得到两个数组的交集。

首要对两个数组进行排序,然后运用两个指针遍历两个数组。

初始时,两个指针分别指向两个数组的头部。每次比较两个指针指向的两个数组中的数字,如果两个数字不持平,则将指向较小数字的指针右移一位,如果两个数字持平,将该数字添加到答案,并将两个指针都右移一位。当至少有一个指针超出数组规模时,遍历完毕。

代码

class Solution {
    func intersect(_ nums1: [Int], _ nums2: [Int]) -> [Int] {
        let newNums1: [Int] = nums1.sorted()
        let newNums2: [Int] = nums2.sorted()
        let length1: Int = newNums1.count
        let length2: Int = newNums2.count
        var intersection: [Int] = []
        var index1 = 0
        var index2 = 0
        while index1 < length1 && index2 < length2 {
            if newNums1[index1] < newNums2[index2] {
                index1 += 1
            } else if newNums1[index1] > newNums2[index2] {
                index2 += 1
            } else {
                intersection.append(newNums1[index1])
                index1 += 1
                index2 += 1
            }
        }
        return intersection
    }
}

复杂度剖析

  • 时刻复杂度:O(mlog⁡m+nlog⁡n)O(m \log m+n \log n),其间 mmnn 分别是两个数组的长度。对两个数组进行排序的时刻复杂度是 O(mlog⁡m+nlog⁡n)O(m \log m+n \log n),遍历两个数组的时刻复杂度是 O(m+n)O(m+n),因而总时刻复杂度是 O(mlog⁡m+nlog⁡n)O(m \log m+n \log n)

  • 空间复杂度:O(min⁡(m,n))O(\min(m,n)),其间 mmnn 分别是两个数组的长度。为返回值创立一个数组 intersection,其长度为较短的数组的长度。不过在 C++ 中,咱们能够直接创立一个 vector,不需求把答案暂时存放在一个额外的数组中,所以这种完成的空间复杂度为 O(1)O(1)

结语

如果 nums2\textit{nums}_2 的元素存储在磁盘上,磁盘内存是有限的,而且你不能一次加载一切的元素到内存中。那么就无法高效地对 nums2\textit{nums}_2 进行排序,因而引荐运用办法一而不是办法二。在办法一中,nums2\textit{nums}_2 只关系到查询操作,因而每次读取 nums2\textit{nums}_2 中的一部分数据,并进行处理即可。