算法描述
前提 | 有序升序数组arr,目标值target |
1 | i=0,j=len-1 设置左右指针 |
2 | 设置中间索引mid=(i+j)/2,mid向下取整 |
3 | target=arr[mid] 返回mid |
4 | target<arr[mid],目标在中间索引前段,j=mid-1,返回步骤2 |
5 | arr[mid]>target,目标在中间索引后端,i=mid+1,返回步骤2 |
6 | i>j,没有找到目标值,返回-1 |
语言描述
在一个升序数组中,设置左索引i,右索引j,和中间值mid,判断目标值与中间值的大小,1)target>中间值,则target在右侧,i=mid+1;2)target<中间值,则target在左侧,j=mid-1;3)target=中间值,返回mid即可
but 如果所有索引都检查了一遍即i>j,还没有找到,则数组中无该索引,返回-1;
时间复杂度 o(log2^n)
代码实现
int j=arr.length-1;不要忘记 -1
public int Search(int[]arr,int target){
int i=0;//左指针
int j=arr.length-1;//右指针
while(i<=j){
int mid=(i+j)/2;//中间数
if(target<arr[mid]){//目标在左侧
j=mid-1;
} else if (arr[mid]<target){//目标在右侧
i=mid+1;
}else {
return mid;//目标=中间值
}
}
return -1;//没找到返回-1
}
思考
1.i<=j与i<j
2.mid=(i+j)/2的隐患
与源码补码有关,所以用mid=i+j>>>1
3.代码只用<号--一种规范,牛
算法改进2.0
改进内容
1.j=arr.len
2.i<j
3.j=mid
代码实现
static int BinarySearch(int[]arr,int target){
int i=0;
int j=arr.length;//1.j
while(i<j){//2.i<=j
int mid=i+j>>>1;
if (target<arr[mid]){
j=mid;//3.j=mid-1
} else if (arr[mid]<target) {
i=mid+1;
}else{
return mid;
}
}return -1;
}
区别.
j含义的改变:
基础:j指向一个元素,也在可查找空间中
进阶:j指向一个边界,不为查找元素
算法改进3.0
代码实现
static int BinarySearch(int[] arr,int target){
int i=0;
int j=arr.length;
while(1<j-i){
int mid=i+j>>>1;
if (target<arr[mid]) {
j=mid;
}else{
i=mid;
}
}
if (arr[i] ==target) {
return i;
}else{
return -1;
}
}
改进地方(相较于2.0)
while(i<j){
int mid=i+j>>>1;
if (target<arr[mid]){ //目标值在左边循环内时间复杂度为L
j=mid;
} else if (arr[mid]<target) { //目标值在右边时间复杂度为2L
i=mid+1;
}else{
return mid;
}
左右两边时间复杂调度不一致,3.0改进判断方式,好处:使左右时间复杂度一致,坏处:当target=arr[mid]出现时,只能循环结束后再判断
时间复杂(logn)
leftmost
引:二分查找算法对重复元素的处理--找到重复元素的最左索引
语言描述
在找到第一个目标值的前提下,向前查找,if还有目标值,则赋值给candidate,并再次向前查找,知道全部都查找一遍(i>j);
代码实现
public int leftmost(int[] arr,int target){
int i=0;//左指针
int j=arr.length-1;//右指针
int candidate=-1;//获取最左索引
while(i<=j){
int mid=(i+j)/2;//中间数
if(target<arr[mid]){//目标在左侧
j=mid-1;
} else if (arr[mid]<target) {//目标在右侧
i=mid+1;
}else {//目标=中间值
candidate=mid;
//因为想找到最左索引,索引要在该目标前找
j=mid-1;
}
}
return candidate;//最后返回找到的最左索引值,如果没找到就返回-1;
}
rightmost
引--想法和leftmost差不多
代码实现
public int rightmost(int[] arr,int target){
int i=0;//左指针
int j=arr.length-1;//右指针
int candidate=1;
while(i<=j){
int mid=(i+j)/2;//中间数
if(target<arr[mid]){//目标在左侧
j=mid-1;
} else if (arr[mid]<target) {//目标在右侧
i=mid+1;
}else {//目标=中间值
candidate=mid;
//因为想找到最右索引,索引要在该目标后找
i=mid+1;
}
}
return candidate;//最后返回找到的最后索引值,如果没找到就返回-1;
}
还有p16,要死了,是什么狗屎的脑筋急转弯