是记录,会有错误,欢迎各位大佬在评论区发表意见
这里是以升序的为例
给出我学习的疑惑
while(l<r)
.....
当nums[mid]
注意:由于区间定义是左闭右开的,left指向的是包含target这个情况的,因为nums[mid] 比如:当nums[mid]>target的时候,target在mid的左边,右边界可以一个必定不等于target的(这里我感觉我理解错了)边界需要更新为[left,mid) 当while是左闭右闭区间的时候,即[left,right] 当 当nums[mid] > target, target在mid的左边,边界需要更新为[left,mid-1],原因上同 这题暴力也是可以的哈 第二条试探过程 nums={1,8};target = 7 nums ={1}; target = -1 提示:我这题是以左闭右开区间写的 找第一次出现的位置 找最后一次的,这个我主要是边界范围极大概率会出错,二分寻找最后一个出现的位置的边界更新的规则如下 nums = {1,2,2,2,2,9},target=2 第二次:l=2,r=5,mid=(l+r)/2=3,a[mid]=2,条件2成立,l更新为mid也就是3 第三次:l=3,r=5,mid=(l+r)/2=4,a[mid]=2,条件2成立,l更新为mid也就是4 第四次:l=4,r=5,mid=(l+r)/2=4,a[mid]=2,条件2成立,l更新为mid也就是4 这里废了 第五次;l=4,r=5,mid=(l+r)/2=4,a[mid]=2,条件2成立,l更新为mid也就是4 接下来试着解释一下原因(部分内容参考了别人的) 好,既然向下取整不行, 分类讨论 就两句话 完整代码nums[mid] < target
, target在mid的右边,边界需要更新为[mid+1,right]
,left为何更新为mid+1
?因为区间定义要求left和right指向的值都要包含等于target的这个情况,mid都比target小,那么mid前面的都比target小LeetCode 35. 搜索插入位置
二分的性质(第二条是试出来的):
nums={1,8}; target = 0
left=0,right=1 初始化
left=0,right=0
left=0,right=-1 出循环了
left=0,right=1 初始化
left=1,right=1
left=1,right=0 出循环了
left=0,right=0 初始化
left=0,right=-1出循环了
试探的过程中发现出循环的left
值就是我们想要的结果LeetCode 34
int search(int[] nums,int target){
int l =0,r=nums.length;
while(l<r){
int mid = (l+r)/2;//这里我没有考虑溢出的情况
if(nums[mid] >=target)//表明第一次出现的位置一定是在mid或者mid前面
r=mid;
else // nums[mid] < target target第一次出现的位置一定是在mid的后面
l=mid+1;
}
return l;
}
a[mid]>target
,表明mid后面的数必定是大于target的,所以r=mid-1
的a[mid]<=target
,表明target在mid的后面(包含mid),所以l=mid
target最后一次
出现的位置
乍一看这好对啊,但是模拟一次哈
0,1,2,3,4,5
第一次: l=0,r=5,mid = (l+r)/2=2,a[mid]=2,条件2满足,l更新为mid也就是2
原因: (l+r)/2是向下取整
的,但是若区间只有两个元素的时候,r=l+1的
,mid = (l+l+1)/2 = (2l+1)/2 = l了,然后就是l更新为了l,没变,导致上次处理的区间和这次处理的区间相同向上取整
试试
这里我好像在csapp那本书上看到过,待会取找找看看,挖坑
l = 4,r=4 (l+r)/2向上取整也等于(l+r+1)/2向下取整
若程序中有l=mid这种情况,mid的计算需用(l+r+1)/2计算
但是右边界也有可能更新为mid啊
若mid = (l+r+1)/2的时候,区间内只有两个元素,
l = r-1, mid = (l+r+1)/2=(r-1+r+1)/2=r
,r更新为r,又废了,所以不能用这个
mid = (l+r)/2
的时候,若出现了l = mid
,程序就废了,将mid用(l+r+1)/2
来计算mid = (l+r+1)/2
的时候,若出现了r = mid
,程序就废了,将mid用(l+r)/2
来计算public int[] searchRange(int[] nums, int target) {
int l =0,r=nums.length-1;
while(l<r){
int mid = l+r>>1;
if(nums[mid]>=target)
r=mid;
else
l=mid+1;
}
if(nums[l]!=target)
return new int[]{-1,-1};
int[] res =new int[2];
res[0]=l;
l=0;
r=nums.length-1;
while(l<r){
int mid = (l+r+1)/2;
if(nums[mid]<=target)
l= mid; // target最后一次出现的位置在mid(含)的后面,调整左边界
else
r= mid-1; // target最后一次出现的位置在mid的前面,调整右边界
}
result[1]=l;
return result;
}