昨天我们做了一道基础的二分查找,是不是觉得很简单? 其实我们用二分查找的时候,往往都是因为他的时间复杂度更优越,但如果没那么明显的题目,你能不能想到用二分查找呢?
题目描述
给定一个按照升序排列的整数数组 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,让我们多体会几遍吧!
这道题就先到这里了,大家加油!