排序数组中找到元素起始|刷题打卡

121 阅读2分钟

昨天我们做了一道基础的二分查找,是不是觉得很简单? 其实我们用二分查找的时候,往往都是因为他的时间复杂度更优越,但如果没那么明显的题目,你能不能想到用二分查找呢?

题目描述

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

示例1

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例2

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

思路分析

这道题其实我们用暴力求解的方式可以更简单的去进行求解,大家应该都是会的。

但是如果说让你把时间复杂度降到logn,你会怎么办呢? 小伙伴们开始想到二分查找,但这和我们之前的不太一样呀,我们怎么我们找到的是左边界或者右边界呢?

让我们来试一下

AC代码


var searchRange = function(nums, target) 
    let res = [-1,-1];
    // 用二分法去进行查找index
    // 左边界和右边界要不同判断
    let leftIndex = findIndex(nums,target,true);
    let rightIndex = findIndex(nums,target,false) - 1;
	// 这里为什么要 -1 呢 因为我们很难直接确定 这个位置是否就是右边界,我们往往只能确定第一个大于target的位置
    if(leftIndex <= rightIndex && nums[leftIndex] == target && nums[rightIndex] == target) {
    	//判断条件不能少
        res = [leftIndex,rightIndex]
    }
    return res;
};

function findIndex(nums,target,isLow) {
    // 这个ans的初始值真是被教育了,刚开始我给他设置了length - 1,但发现某些时候 我们的右边界会出错
    let left = 0,right = nums.length - 1,ans = nums.length;
    while(left <= right) {
        let mid = (left + right) >>> 1;
        // 这里其实也是需要注意的 如果刚开始就判断mid是否大于target。left右移的话 你会发现难以为继,因为想找左边界是要像左推进的
        if(nums[mid] > target || (isLow && nums[mid] >= target)) {
            right = mid - 1;
            ans = mid
        } else {
            left = mid + 1;
        }
    }
    return ans
}


总结

其实这道题我在做的时候,踩了两个坑,正因如此,我们才要不断进步呀

在确定用二分查找的时候,我们要想好二分查找去做的事情,这道题就是返回相应的index,让我们多体会几遍吧!

这道题就先到这里了,大家加油!