大家好!我是曾续缘❣️
今天是《LeetCode 热题 100》系列
发车第 63 天
二分查找第 1 题
❤️点赞 👍 收藏 ⭐再看,养成习惯
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为
O(log n)
的算法。示例 1:
输入: nums = [1,3,5,6], target = 5 输出: 2示例 2:
输入: nums = [1,3,5,6], target = 2 输出: 1示例 3:
输入: nums = [1,3,5,6], target = 7 输出: 4提示:
难度:❤️
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums
为 无重复元素 的 升序 排列数组-104 <= target <= 104
解题方法
题目要求我们在一个已经排序的数组中找到目标值,并返回它的索引。如果目标值不在数组中,我们需要返回它应该插入的位置。为了达到题目要求的时间复杂度
二分查找是一种高效的查找算法,它每次将查找区间减半,适用于有序数组。算法的基本思想是:
- 初始化两个指针:
l
(左指针)和r
(右指针),分别指向数组的起始和结束位置。左指针表示可能的插入位置的下界,右指针表示上界。 - 计算中间位置:在每次循环中,计算
l
和r
的中间位置mid
,即(l + r) / 2
。将中间位置的元素与目标值进行比较。 - 比较中间元素与目标值:
- 如果中间元素
nums[mid]
等于目标值target
,则直接返回mid
,因为找到了目标值。 - 如果
nums[mid]
大于target
,说明目标值应该在左半部分,我们将右指针r
移动到mid - 1
的位置。 - 如果
nums[mid]
小于target
,说明目标值应该在右半部分,我们将左指针l
移动到mid + 1
的位置。
- 如果中间元素
- 重复上述过程:继续在更新后的区间内进行二分查找,直到找到目标值或者
l
大于r
。 - 返回结果:
- 如果在数组中找到了目标值,算法会在找到目标值时立即返回其索引。
- 如果目标值不在数组中,当
l
大于r
时循环结束,此时l
指向的就是目标值应该插入的位置。
我们使用的是左闭右闭 [l, r]
的区间方式。这种方式在处理边界值时比较直观,因为不需要担心数组越界的问题。当 l
和 r
相等时,区间中仍然包含一个元素,这也是为什么循环条件是 l <= r
的原因。当 nums[mid]
不等于 target
时,更新指针时,l
会设置为 mid + 1
,r
会设置为 mid - 1
,因为中间值 mid
已经被检查过了,不需要再次检查。
在二分查找算法中,区间的开闭指的是在每一步迭代中,是否包含区间的边界值。具体来说,区间可以是左闭右闭 [l, r]
、左闭右开 [l, r)
、左开右闭 (l, r]
或者左开右开 (l, r)
。在实现二分查找时,选择哪种区间开闭方式会影响循环条件和指针更新的方式。
左闭右闭 [l, r]
- 初始条件:
l = 0
,r = n - 1
- 循环条件:
l <= r
- 左指针更新:
l = mid + 1
- 右指针更新:
r = mid - 1
左闭右开 [l, r)
- 初始条件:
l = 0
,r = n
- 循环条件:
l < r
- 左指针更新:
l = mid + 1
- 右指针更新:
r = mid
左开右闭 (l, r]
- 初始条件:
l = -1
,r = n - 1
- 循环条件:
l < r
- 左指针更新:
l = mid
- 右指针更新:
r = mid - 1
左开右开 (l, r)
- 初始条件:
l = -1
,r = n
- 循环条件:
l + 1 < r
- 左指针更新:
l = mid
- 右指针更新:
r = mid
Code
查看代码
java
class Solution {
public int searchInsert(int[] nums, int target) {
int n = nums.length;
int l = 0, r = n - 1;
while(l <= r){
int mid = (l + r) / 2;
if(nums[mid] == target){
return mid;
}else if(nums[mid] > target){
r = mid - 1;
}else{
l = mid + 1;
}
}
return l;
}
}