关于hash:分享一个简单但挺有意思的算法题哈希二分双指针

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)

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理