1. 题目描述

给你两个有序(递增)整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集,M为较长数组长度,N为较短数组长度。例如:
给定:nums1 = [1,2,3,4,5,6], nums2 = [1,2,3]
输出:[1,2,3]
这道题常见且并不难,有意思的是解法非常多,在nums1 和 nums2长短不同场景下,挑选最高效的解法

2. 哈希表

这是最容易想到的解法,对较短的数组进行哈希,遍历较长的数组,就可以得到交集

function intersect(nums1, nums2){
    let hash = new Set()//这里用set来代表哈希,他们本质是一样的
    for (let i = 0; i < nums2.length; i++) {
        hash.add(nums2[i])
    }
    for (let i = 0; i < nums1.length; i++) {
        if (hash.has(nums1[i])) {
            ans.push(nums1[i])
        }
    }
    return ans
}

时间复杂度:O(M+N)<br/>
空间复杂度:对于较短的数组进行了哈希,O(N)

3. 二分查找

思考一个场景,较长的数组非常长,哈希表的解法是线性的,显然没有很好的利用数组有序这个条件,这时二分查找脱颖而出,因为两者长度相差越大,二分效率越高;

function intersect(nums1, nums2){
    //由于是递增,定义一个left,稍微减少下查找范围
    let left = 0;
    for (let i = 0; i < nums2.length; i++) {
                
        //二分查找
        let index = binarySearch(nums1, nums2[i], left)
        if (index != -1) {
            ans.push(nums2[i])
            left = index + 1
        }
    }    
    return ans
}

function binarySearch(nums, target, left  = 0, right = nums.length - 1){
        //特殊处理 端点的情况 可以加速连续数组的查找
        if(nums[left] == target){
            return left
        }
        if(nums[right] == target){
            return right
        }
    while(left <= right){
        mid =  Math.floor((left + right)/2)
        if (nums[mid] == target) {
            return mid
        }else if(nums[mid] > target){
            right = mid - 1
        }else{
            left = mid + 1
        }
    }
    return -1
}
这里重点提一下为什么要优化二分查找的左起点,如果我们不给定左起点,那么每次二分都是从0len -1二分,而由于数组是有序的,如果已经在num1中找到了target,那么下一个待查找target的位置必然在上一个target的右边,这样就避免了二分查找每次从0开始,最理想情况下比如nums1 = [1,2,3,4,5,6], nums2 = [4,5,6],第一次查找到4,剩余的5,6显然在4的右边,实际只要O(N)次就可以了
时间复杂度:M为较长数组长度,N为较短数组长度,最差/平均复杂度O(N*logM),而且由于我们优化了二分查找的左起点,最最理想情况下复杂度可以达到O(N);不是理想情况下,时间复杂度取决于交集在nums1中的分布情况,交集在nums1中越靠右分布,查找效率越高<br/>
空间复杂度:如果递归数组是引用的话,我们只使用了常量级变量空间 O(1)

4. 双指针

如果两个数组长度相差不大,那么双指针显然效率更高;

function intersect(nums1, nums2){
    let m = n = 0
    while( m < nums1.length && n < nums2.length ) {
        if (nums1[m] == nums2[n]) {
            ans.push(nums1[m])
            m++
            n++
        }else if (nums1[m] > nums2[n]) {
            n++
        }else{
            m++
        }
    }
    return ans
}

时间复杂度:M为较长数组长度,N为较短数组长度,最好情况是O(N),最坏情况是O(M)<br/>
空间复杂度: 只使用了常量级变量空间 O(1)


tfzh
231 声望17 粉丝

code what u love & love what u code


引用和评论

0 条评论