【数组取交集】|刷题打卡

334 阅读4分钟

柿子挑软的捏,所以我就先拿最软的来作为我小白的第一道,大佬求不要喷我。我只想买拿个一折优惠卷买两本小测。揪咪

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

两个数组的交集-349

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]

说明:

输出结果中的每个元素一定是唯一的。 我们可以不考虑输出结果的顺序。

前言:

在看到标题(取交集)中,我们脑海中会闪过那些数组的迭代方法,every()\some()\filter()\map()\forEach()\reduce()\find()\includes()\indexOf()等等等...

又看到我们现在有去重和不重两种。Es6最直观 Set去重。虽然无法去掉'{}'控对象,但我们现在也不考虑,或者遍历,利用indexOf、利用includes,甚至利用对象key的唯一性去去重,我们这里不在延伸,有兴趣,自行解决,嘿嘿。

脑海中闪过第一种解决方案:

var intersection = function(nums1, nums2) {
	return [...new Set(nums1)].filter(item => nums2.includes(item));
};

心中暗暗窃喜一行代码就解决了,执行代码,提交,完事,下一道。

这里呢,我脑海中甚至都没有时间复杂度的概念,这时候跟暑假写作业一样,写完翻到最后找答案呀,立马答案对起来,我们官方题解立马摘抄出来给大家。

思路想法

计算两个数组的交集,直观的方法是遍历数组 nums1,对于其中的每个元素,遍历数组 nums2 判断该元素是否在数组 nums2 中,如果存在,则将该元素添加到返回值。假设数组 nums1 和 nums2 的长度分别是 mm 和 nn,则遍历数组 nums1 需要 O(m) 的时间,判断 nums1 中的每个元素是否在数组 nums2 中需要 O(n) 的时间,因此总时间复杂度是 O(mn)。

哈希表解法

如果使用哈希集合存储元素,则可以在 O(1) 的时间内判断一个元素是否在集合中,从而降低时间复杂度。

首先使用两个集合分别存储两个数组中的元素,然后遍历较小的集合,判断其中的每个元素是否在另一个集合中,如果元素也在另一个集合中,则将该元素添加到返回值。该方法的时间复杂度可以降低到 O(m+n)。

var intersection = function(nums1, nums2) {
   const set1 = new Set(nums1);
   const set2 = new Set(nums2);
   return set_intersection(set1, set2)
};

function set_intersection(set1, set2){
    if(set2.length > set1.length) {
        return set_intersection(set2, set1);
    }
    const intersection = new Set();
    for(let num of set1){
        set2.has(num) && intersection.add(num);
    }
    return [...intersection];
}

这里利用哈希表我觉得更有助于我们理解整个流程,找到去重后最短的数组,声明一个新数组,遍历找到另外一个数组所共同拥有的数值,然后返回我们的新数组。

哈希表复杂度分析

  • 时间复杂度:O(m+n),其中 m 和 n 分别是两个数组的长度。使用两个集合分别存储两个数组中的元素需要 O(m+n) 的时间,遍历较小的集合并判断元素是否在另一个集合中需要 O(min(m,n)) 的时间,因此总时间复杂度是 O(m+n)。

  • 空间复杂度:O(m+n),其中 m 和 n 分别是两个数组的长度。空间复杂度主要取决于两个集合。

排序 + 双指针解法

我觉得排序与双指针用大白话来说就是,先把数组排序,大家头对头,脚对脚来进行对比,第一步对比,ok,你头大你牛皮,我找我老大(下一个,较小数字指针向右移一位),大家头一样大,好的存起来(同时将两个指针右移一位),最后大家再令出来,大家一起看~

代码copy出来~

var intersection = function(nums1, nums2) {
    nums1.sort((x, y) => x - y);
    nums2.sort((x, y) => x - y);
    const length1 = nums1.length, length2 = nums2.length;
    let index1 = 0, index2 = 0;
    const intersection = [];
    while (index1 < length1 && index2 < length2) {
        const num1 = nums1[index1], num2 = nums2[index2];
        if (num1 === num2) {
            // 保证加入元素的唯一性
            if (!intersection.length || num1 !== intersection[intersection.length - 1]) {
                intersection.push(num1);
            }
            index1++;
            index2++;
        } else if (num1 < num2) {
            index1++;
        } else {
            index2++;
        }
    }
    return intersection;
};

排序+双指针复杂度分析

  • 时间复杂度:O(mlogm+nlogn),其中 m 和 n 分别是两个数组的长度。对两个数组排序的时间复杂度分别是 O(mlogm) 和 O(nlogn),双指针寻找交集元素的时间复杂度是 O(m+n)O(m+n),因此总时间复杂度是 O(mlogm+nlogn)。

  • 空间复杂度:O(logm+logn),其中 m 和 n 分别是两个数组的长度。空间复杂度主要取决于排序使用的额外空间。 ”本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情