启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情
近日,在LeetCode上刷每日一题时,有感自身积累不足,面对简单和中等的题型往往很快会有思路,并且能不断的优化,但是面对困难题型便束手无策了,于是制定刷题顺序,进行连贯性刷题。
题目来源
题目描述(简单)
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例1
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例2
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
提示
- 你可以假设
nums中的所有元素是不重复的。 n将在[1, 10000]之间。nums的每个元素都将在[-9999, 9999]之间。
题目解析
二分查找
该题是一道原汁原味的二分搜索法,并且该题的前提是数组为有序数组,并且强调了数组无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的。
这些都是二分查找法的前提条件,当题目描述满足以上条件时,就可以考虑二分查找法了。
同时,二分查找法的关键在于边界条件的处理
例如
while (left < right)和while (left < =right)right = middle和right = middle - 1到底选择哪一个呢
这时只需要坚持循环不变量规则,即在循环中每一次边界的处理都要坚持根据 区间的定义(不变量(左闭右闭或者左闭右开)) 来操作。
根据题意,在升序数组 nums 中寻找目标值 target ,对于特定下标 i ,比较 nums[i] 和 target 的大小:
- 如果
nums[i] = target,则下标i为要寻找的小标 - 如果
nums[i] > target,则target只可能出现在下标i的左侧 - 如果
nums[i] < target,则target只可能出现在下标i的右侧
左闭右闭
定义查找的区间 [left,right] ,每次取查找范围的中点 mid ,比较 nums[mid] 和 target 的大小,依据上述事实,返回下标或者缩小范围。
此时区间为左闭右闭,你会发现在此区间中
left === right的情况是有意义的,所以边界条件如下:
while (left <= right)right = mid - 1left = mid + 1right = nums.length - 1
代码
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function(nums, target) {
let left = 0, right = nums.length - 1
while (right >= left) {
let mid = Math.floor((left + right + 1) / 2)
if (nums[mid] > target) {
right = mid - 1
}else if(nums[mid] < target){
left = mid + 1
}else{
return mid
}
}
return -1
};
如图:
左闭右开
定义查找的区间 [left,right] ,每次依旧取查找范围的中点 mid 。
此时区间为左闭右开,你会发现此区间中
left === right是没有意义的。所以边界条件如下:
while (left < right)right = nums.lengthleft = mid + 1right = mid
代码
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function(nums, target) {
let left = 0, right = nums.length
while (right > left) {
let mid = Math.floor((left + right) / 2)
if (nums[mid] > target) {
right = mid
}else if(nums[mid] < target){
left = mid + 1
}else{
return mid
}
}
return -1
};
如图:
当然还有左开右闭的情况,不过这种情况十分少见,也依旧遵循循环不变量规则,感兴趣的小伙伴可以尝试一下,这里不再赘述了。
相关题目推荐
- LeetCode —— 35. 搜索插入位置 - 掘金
- LeetCode —— 34. 在排序数组中查找元素的第一个和最后一个位置 - 掘金
- LeetCode —— 69. x 的平方根 - 掘金
- LeetCode —— 367. 有效的完全平方数 - 掘金
执行用时和内存消耗仅供参考,大家可以多提交几次。如有更好的想法,欢迎大家提出。