题目
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2] 输出:[2,2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4] 输出:[4,9]
说明:
- 输出结果中每个元素出现的次数,应与元素在两个数组中出现次数的最小值一致。
- 我们可以不考虑输出结果的顺序。
思路
我们可以把其中一个数组构建成一个哈希表,然后通过遍历另一个数组找到交集,并将交集元素存入一个结果数组中返回。
Map<Integer,Integer> map = new HashMap<>();//哈希表
int[] result = new int[nums1.length];//结果数组
细节一
- 时间复杂度是 O(m + n) ,其中 m 和 n 分别为两个数组的长度,耗时主要在建表和遍历上。
- 而空间主要耗在哈希表上,所以我们要考虑将长度较短的数组拿来建表,可得空间复杂度为 O(min(m,n)) 。
- 为了方便编码,我们规定 nums1 始终是元素较少的那个数组,如果不符合我们必须考虑首先将两数组位置进行交换。
//保证nums1永远都是元素少的那个数组
if (nums1.length > nums2.length) {
return intersect(nums2, nums1);
}
细节二
- 我们并不清楚交集元素的个数,但显然它必定不会超过 nums1 的元素个数,所以我们将 nums1 的长度作为结果数组的长度。
- 在最后我们需要考虑截断结果数组再 return。
//截断至结果数组最后一个有效数据并返回
return Arrays.copyOfRange(result,0,index);
方法介绍
Arrays.copyOfRange(T[] original,int from,int to)
将一个原始的数组 original ,从下标 from 开始复制,复制到下标 to ,生成一个新的数组。
注意这里包括下标 from ,但不包括下标 to 。
代码
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
//保证nums1永远都是元素少的那个数组
if (nums1.length > nums2.length) {
return intersect(nums2, nums1);
}
Map<Integer,Integer> map = new HashMap<>();
int[] result = new int[nums1.length];//结果数组(可以肯定其大小肯定小于或等于nums1的大小)
int index = 0;//结果数组的下标
//使用哈希表记录nums1的元素类型和元素个数
for (int i = 0; i < nums1.length; i++) {
if (!map.containsKey(nums1[i])) {
map.put(nums1[i],1);
} else {
map.replace(nums1[i],map.get(nums1[i]) + 1);
}
}
//通过查表和遍历nums2寻找交集
for (int i = 0; i < nums2.length; i++) {
if (map.containsKey(nums2[i]) && map.get(nums2[i]) > 0) {
result[index] = nums2[i];
map.replace(nums2[i],map.get(nums2[i]) - 1);
index++;
}
}
//截断至结果数组最后一个有效数据并返回
return Arrays.copyOfRange(result,0,index);
}
}