题目:给定两个数组,编写一个函数来计算它们的交集。
说明:
1.输出结果中每个元素出现的次数,应与元素在两个数组中出现次数的最小值一致
2.不考虑输出结果顺序
示例:
输入:num1=[1,2,2,1] , nums2=[2,2]
输出:[2, 2]
思路:对于我来说,这样类似的题,我上来就是一顿双重For循环遍历, 哈哈。 不过在遍历的时候,还要注意num2层的数据不能重复匹配。 加入nums2=[2] ,那么就只能匹配num1中的一个2,而不能匹配两个,所以要注意维护下num2中被匹配的元素,你可以使用一个set来记录相关下标。
Set<Integer> set = new HashSet<>();
for (int i = 0; i < nums1.length; i++) {
for (int j = 0; j < nums2.length; j++) {
if (nums1[i] == nums2[j]) {
if (!set.contains(j)) {
set.add(j);
break;
}
continue;
}
}
}
int size = set.size();
int[] a = new int[size];
for (int n : set) {
a[--size] = nums2[n];
}
return a;
虽然上面双重For循环可以解决问题,但是我们还是要思考下更优解。
题目多思考几次就可以看出我们不用管结果顺序,只要求出元素在两个数组中出现的公共次数就行了,那么我们可以先统计NUM1中出现的次数,在遍历num2中出现的次数即可。 空间换时间,增加一个Map结构来存num和其出现次数的映射。
public static int[] intersect3(int[] nums1, int[] nums2) {
if(nums1.length > nums2.length){
//减少空间复杂度,Map存储短的数组
return intersect3(nums2, nums1);
}
Map<Integer, Integer> map = new HashMap<>();
// 遍历构建num1 Map
for (int n : nums1){
int count = map.getOrDefault(n, 0) + 1;
map.put(n, count);
}
int[] res = new int[nums1.length];
int index = 0;
//根据map和nums2 构建res[]
for (int num : nums2){
int count = map.getOrDefault(num , 0);
if(count > 0){
res[index++] = num;
count--;
if(count > 0){
map.put(num, count);
}else {
map.remove(num);
}
}
}
return Arrays.copyOfRange(res, 0, index);
}
每次在使用暴力解法后(解后圣如佛),还是得思考下更优解是什么。
这里有一个进阶题,若num1和num2是已经排好序的数组,那么更优解是什么?
下篇解答 : )