Easy
题目描述
给你两个整数数组 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]
解释:[9,4] 也是可通过的
提示:
1 <= nums1.length, nums2.length <= 10000 <= 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 的长度。哈希表方法是最优解,具有线性时间复杂度。