题目
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]
说明:
输出结果中每个元素出现的次数,应与元素在两个数组中出现次数的最小值一致。
我们可以不考虑输出结果的顺序。
进阶:
如果给定的数组已经排好序呢?你将如何优化你的算法?
如果 nums1 的大小比 nums2 小很多,哪种方法更优?
如果 nums2 的元素存储在磁盘上,内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?
解题思路
本题可以使用哈希表来解决。首先遍历第一个数组,并将每个元素及其出现的次数存储在哈希表中。然后遍历第二个数组,在哈希表中查找相同的元素,如果存在且出现次数大于 0,则将该元素添加到结果数组中,并将其出现次数减一。
具体实现方式为:
- 创建一个哈希表
map。 - 遍历第一个数组
nums1,并将每个元素及其出现次数存储在map中。 - 创建一个空数组
result。 - 遍历第二个数组
nums2,并在map中查找对应元素,如果存在且出现次数大于 0,则将该元素添加到result中,并将其出现次数减一。 - 返回
result数组作为最终的交集结果。
代码实现
function intersect(nums1: number[], nums2: number[]): number[] {
const map = new Map();
for (const num of nums1) {
if (!map.has(num)) {
map.set(num, 0);
}
map.set(num, map.get(num) + 1);
}
const result: number[] = [];
for (const num of nums2) {
if (map.has(num) && map.get(num) > 0) {
result.push(num);
map.set(num, map.get(num) - 1);
}
}
return result;
}
也可以双指针法
function intersect(nums1: number[], nums2: number[]): number[] {
nums1.sort((a, b) => a - b);
nums2.sort((a, b) => a - b);
const result: number[] = [];
let p1 = 0;
let p2 = 0;
while (p1 < nums1.length && p2 < nums2.length) {
if (nums1[p1] === nums2[p2]) {
result.push(nums1[p1]);
p1++;
p2++;
} else if (nums1[p1] < nums2[p2]) {
p1++;
} else {
p2++;
}
}
return result;
}
复杂度分析
- 时间复杂度:O(n + m),其中 n 和 m 分别是两个输入数组的长度。遍历第一个数组需要 O(n) 的时间,构建哈希表的过程中需要 O(n) 的时间;遍历第二个数组需要 O(m) 的时间,在哈希表中查找元素的过程中需要 O(1) 的时间。
- 空间复杂度:O(min(n, m)),其中 n 和 m 分别是两个输入数组的长度。哈希表中存储了较短数组的元素及其出现次数。最坏情况下,当两个数组没有交集时,哈希表中存储的元素为较短数组的所有元素。