更加严谨的二分
- 使用场景
- 满足类似的条件,需要找的某个数>=target
- 或者<=target
- 一般的二分
- 只会判断是否满足==的条件
- 对于边界的点会舍弃
- 造成有可能找不到正确的答案
二分模板
- 判断>=target 的情况
// 序列为0-n-1
// 为什么设置n,n为不合法的情况,即没有比target还要大的
let left=0
let right=n
while(left<right){
let mid=(left+right)>>1
if(nums[mid]>=target){
right=mid
}else{
left=mid+1
}
}
return right
- 判断<=target的情况
// 这里-1也是为了进行边界处理
left=-1
right=nums.length-1
while(left<right){
let mid=(left+right+1)>>1
if(nums[mid]<=target){
left=mid
}else{
right=mid-1
}
}
return right
34. 在排序数组中查找元素的第一个和最后一个位置
给你一个按照非递减顺序排列的整数数组 nums
,和一个目标值 target
。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target
,返回 [-1, -1]
。
你必须设计并实现时间复杂度为 O(log n)
的算法解决此问题。
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
示例 3:
输入:nums = [], target = 0
输出:[-1,-1]
提示:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums
是一个非递减数组-109 <= target <= 109
解题思路
1. 其实是查找>=target 的第一个数
2. 和<=target 的最后一个数
完整代码
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var searchRange = function(nums, target) {
// 问题本质在于求>=target 的第一个数
// 和<=target 的最后一个数
let left=0
let right=nums.length
let res=[]
while(left<right){
let mid=(left+right)>>1
if(nums[mid]>=target){
right=mid
}else{
left=mid+1
}
}
if(nums[right]!==target) right=-1
res.push(right)
left=-1
right=nums.length-1
while(left<right){
let mid=(left+right+1)>>1
if(nums[mid]<=target){
left=mid
}else{
right=mid-1
}
}
if(nums[right]!==target) right=-1
res.push(right)
return res
};
153. 寻找旋转排序数组中的最小值(二分查找的变种)
已知一个长度为 n
的数组,预先按照升序排列,经由 1
到 n
次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7]
在变化后可能得到:
- 若旋转
4
次,则可以得到[4,5,6,7,0,1,2]
- 若旋转
7
次,则可以得到[0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], ..., a[n-1]]
旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]]
。
给你一个元素值 互不相同 的数组 nums
,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
你必须设计一个时间复杂度为 O(log n)
的算法解决此问题。
示例 1:
输入:nums = [3,4,5,1,2]
输出:1
解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。
示例 2:
输入:nums = [4,5,6,7,0,1,2]
输出:0
解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组。
示例 3:
输入:nums = [11,13,15,17]
输出:11
解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。
提示:
n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
nums
中的所有整数 互不相同nums
原来是一个升序排序的数组,并进行了1
至n
次旋转
解题思路
1. 需要将题目抽象一下
2. 二分不仅仅只是在一个有序数组中查找某个值
3. 是一种思想,满足条件的放右边,不满足的放左边(舍弃)
4. 本题旋转后的数组,部分有序
5. 本质是找满足<=最后一个元素 的第一个元素(下标靠前的)
完整代码
/**
* @param {number[]} nums
* @return {number}
*/
var findMin = function(nums) {
// 旋转后的数组部分有序
3,4,5|1,2
// 观察可以得出二分的条件
// 即<=2 的第一个元素
4,5,6,7|0,1,2
// <=2 的第一个元素
let left=0
let right=nums.length-1
while(left<right){
let mid=Math.floor((left+right)/2)
if(nums[mid]<=nums[nums.length-1]){
// 当前的mid满足小于2
// 是不是之前的也满足
// 我们向左缩小范围
right=mid
}else{
left=mid+1
}
}
return nums[right]
};
标签:二分,right,target,nums,mid,数组,left
From: https://www.cnblogs.com/lingxin1123/p/17087605.html