Easy

题目描述

给你两个整数数组 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]
解释:[9,4] 也是可通过的

提示:

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

进阶:

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

解题思路

本题可以使用多种方法求解,核心思路是统计每个元素在两个数组中的出现次数,然后取较小值。

方法一:哈希表(推荐) 使用哈希表统计其中一个数组中每个元素的出现次数,然后遍历另一个数组,如果元素在哈希表中存在且计数大于0,就将该元素加入结果并减少计数。这种方法时间复杂度为O(m+n),空间复杂度为O(min(m,n))。

方法二:排序 + 双指针 将两个数组排序后,使用双指针分别指向两个数组的开头。比较两个指针指向的元素:如果相等则加入结果并移动两个指针;如果不等则移动指向较小元素的指针。这种方法时间复杂度为O(mlogm + nlogn),空间复杂度为O(1)(不考虑排序空间)。

选择策略:

  • 当数组已排序时,优先使用双指针方法
  • 当其中一个数组很小时,用小数组建立哈希表更节省空间
  • 当数组很大无法完全加载到内存时,可以使用外部排序 + 双指针

代码实现

class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        unordered_map<int, int> count;
        vector<int> result;
        
        // 统计nums1中每个元素的出现次数
        for (int num : nums1) {
            count[num]++;
        }
        
        // 遍历nums2,查找交集
        for (int num : nums2) {
            if (count[num] > 0) {
                result.push_back(num);
                count[num]--;
            }
        }
        
        return result;
    }
};
class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
        from collections import Counter
        
        count1 = Counter(nums1)
        result = []
        
        for num in nums2:
            if count1[num] > 0:
                result.append(num)
                count1[num] -= 1
        
        return result
public class Solution {
    public int[] Intersect(int[] nums1, int[] nums2) {
        Dictionary<int, int> count = new Dictionary<int, int>();
        List<int> result = new List<int>();
        
        // 统计nums1中每个元素的出现次数
        foreach (int num in nums1) {
            if (count.ContainsKey(num)) {
                count[num]++;
            } else {
                count[num] = 1;
            }
        }
        
        // 遍历nums2,查找交集
        foreach (int num in nums2) {
            if (count.ContainsKey(num) && count[num] > 0) {
                result.Add(num);
                count[num]--;
            }
        }
        
        return result.ToArray();
    }
}
var intersect = function(nums1, nums2) {
    const count = new Map();
    const result = [];
    
    // 统计nums1中每个元素的出现次数
    for (const num of nums1) {
        count.set(num, (count.get(num) || 0) + 1);
    }
    
    // 遍历nums2,查找交集
    for (const num of nums2) {
        if (count.get(num) > 0) {
            result.push(num);
            count.set(num, count.get(num) - 1);
        }
    }
    
    return result;
};

复杂度分析

解法时间复杂度空间复杂度
哈希表O(m + n)O(min(m, n))
排序 + 双指针O(m log m + n log n)O(1)

其中 m 和 n 分别是 nums1 和 nums2 的长度。哈希表方法是最优解,具有线性时间复杂度。

相关题目