给定两个数组,编写一个函数来计算它们的交集。

示例 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 的元素存储在磁盘上,磁盘内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?

方法一 利用Map

这个利用Map原因是,数组里面可能有重复元素,但是Set结构里面是不能有重复的元素。
新建一个res来保存两个数组重叠的交集,在主函数中首先判断下谁的数组长度比较短,短的那一个为Map对象的复制体(如果两个数组的元素数目相差很多的话,优势就会体现出来,额外的空间就很少很多。你懂得!)
Map复制完以后,接下来的for循环就是遍历另一个数组.与map中的元素进行比较,相同的话,把元素从map中删除,同时把该元素放入我们的res数组中。在对map相减的时候,对map的长度进行判断,如果为0,就提前结束循环(刚好他们重复的元素都在数组的前半部分呢?这样后面就可以不再遍历了,特殊情况下还是可以减少时间的)

  var intersect = function(nums1, nums2) {
let res = [];
let map = {};
if (nums1.length < nums2.length) {
for (let e of nums1) {
map[e] = map[e] + 1 || 1;

}
for (let e of nums2) {
if (map[e]) {
res.push(e);
map[e]--;
if(map.size==0)
{break;}
}
}
} else {
for (let e of nums2) {
map[e] = map[e] + 1 || 1;

}
for (let e of nums1) {
if (map[e]) {
res.push(e);
map[e]--;
if(map.size==0)
{break;}
}
}
}

return res;
};

方法二 对两者进行排序,双指针移动法

牵扯事先排序,那么该算法肯定不是最优先解,谁知道排序会占用多少时间呢?这里我们就把方法归结于暴力破解吧,虽然代码投机取巧,但是复杂度不小
思路:排完序以后两个数组内的元素都是从小到大排列的,这时候用两个指针i,j来遍历数组。这里的i,j是指数组的索引,当数组中的两个都相同的,把该元素加入arr数组,然后两个指针都相加。相反,谁的值小,谁的指针移动(这就是为什我们要排序的目的)

var intersect = function(nums1, nums2) {
nums1.sort((x, y) => x - y)
nums2.sort((x, y) => x - y)
let i = 0,
j = 0;
let arr = []
while (i < nums1.length && j < nums2.length) {
if (nums1[i] == nums2[j]) {
arr.push(nums1[i]);
i++;
j++
} else if (nums1[i] > nums2[j]) { j++ } else { i++ }

}
return arr
};

方法三 暴力破解(这个是真正的暴力破解)
两个for循环解决,时间复杂度是真的高。面试遇到,你给面试官说个这个方法(并且你就知道这一种)嘿嘿,那么你的博客就会多上一篇凉凉面经!
下面的代码没有测试,思路就是那样,不建议大家掌握这种,只会暴力,那还学算法干嘛


var intersect = function(nums1, nums2) {

let map = new Map()
let arr = []
for (let i = 0; i < nums1.length; i++) {
for (let j = 0; j < nums2.length; j++) {
if (nums2[j] == nums1[i]) {
arr.push(nums1[i])
map.delete(nums1[i])
map.set(nums1[i])
break; //退出本次循环,找到重复的,后面再出现重复的,我也不会添加
}
}
}
return arr
}