CSP初赛复习-25-二分查找-变形
二分查找变形
除了经典的二分查找以外,还有如下4种变形经常出现
1 查找target出现的第一个位置
第一个等于target的下标
target=3时,查询3第1次出现的下标

大致思路
1 每次区间缩小一半,取中间下标,通过中间下标对应的值和target比较 中间数<target 目标数在右半部分 否则在左半部分
2 中间数<target ,一定没找到 ,如果中间数>=target 可能找到了,继续向左收缩找最小的
3 最后的结果一定是left,而right不符合,因为最后一次找到后又进行来mid-1
#include <bits/stdc++.h>
using namespace std;
/* array查找数组 元素可能重复 size 为array数组元素个数 target待查找数字
实现使用左闭右闭区间
*/
int equalAndGreater(int array[],int size,int target) {
int left = 0, right = size - 1;// 左右区间0 ~ size-1 总共size个元素
while (left <= right) {//边界left=right
int mid=(left+right)/2;
if (array[mid]<target){//小于target时 left=mid+1继续查找 和右区间收缩相遇 因此left是最终结果
left=mid+1;
} else {//相等时会不断向左收缩
right=mid-1;
}
}
return left;//相等会不断向左收缩 不等的left最终和right相等为最终结果
}
int main(){
int a[]={0,1,2,3,3,3,3,4,5,6};//测试数据总共有9个元素 其中包括4个3是重复元素
int size=sizeof(a)/sizeof(a[0]);//sizeof 计算字节数 通过数组的总字节数/第1个元素字节数计算数组元素个数
int ret = equalAndGreater(a,size,3);
cout<<ret;
}
/*
输出
3
*/
2 求第一个大于target的下标
求最后一个target元素下标+1
target=3时,查询第1个大于3的数的下标

大致思路
1 每次区间缩小一半,取中间下标mid,通过中间下标对应值a[mid]和target比较,a[mid]<=target 向右收缩区间(包括a[mid]=target)
2 如果数组元素有重复的,会一直向右收缩,直到最后一个
3 最终向右收缩和向左收缩相遇在最后一个target,此时循环结束,返回的left是最后一个target下标+1(因为left=mid+1 又加了1次)
#include <bits/stdc++.h>
using namespace std;
/*
array查找数组 元素可能重复 size 为array数组元素个数 target待查找数字
实现使用左闭右闭区间
*/
int firstGreater(int array[],int size,int target) {
int left=0, right =size-1;// 左右区间0 ~ size-1 总共size个元素
while (left<=right) {//边界left=right
int mid =(left+right)/2;
//比target小则不断向右收缩区间 相等也向右收缩
if (array[mid]<=target){//最后和target相等终止,
left=mid+1;//最后一个target时,left进行1次left=mid+1
}else{//向左收缩 相遇在最后1个target
right=mid-1;
}
}
return left;//和最后1个target相等后,下标加1
}
int main(){
int a[]={0,1,2,3,3,3,3,4,5,6};//测试数据总共有9个元素 其中包括4个3是重复元素
int size=sizeof(a)/sizeof(a[0]);//sizeof 计算字节数 通过数组的总字节数/第1个元素字节数计算数组元素个数
int ret = firstGreater(a,size,3);
cout<<ret;
}
/*
输出
7
*/
3 查找第一个小于target的值的下标
求第1个target元素下标-1

大致思路
1 每次区间缩小一半,取中间下标mid,通过中间下标对应值a[mid]和target比较,a[mid]>=target 向左收缩区间(包括a[mid]=target)
2 如果数组元素有重复的,会一直向左收缩,直到最后一个
3 最终向左收缩和向右收缩相遇在最前一个target,此时循环结束,返回的right是最后一个target下标-1(因为right=mid-1 又减了1次)
#include <bits/stdc++.h>
using namespace std;
/* array查找数组 元素可能重复 size 为array数组元素个数 target待查找数字
实现使用左闭右闭区间
*/
int firstLess(int array[],int size,int target) {
int left=0, right =size-1;// 左右区间0 ~ size-1 总共size个元素
while (left<=right) {//边界left=right
int mid =(left+right)/2;
if (array[mid]>=target){//相等在这个分支 最终又mid-1了,但需要求target前面一个 所以right符合
right=mid-1;
}else{//相等不在这边 后面mid+1最终一定会相等
left=mid+1;
}
}
return right;//返回下标
}
int main(){
int a[]={0,1,2,3,3,3,3,4,5,6};//测试数据总共有9个元素 其中包括4个3是重复元素
int size=sizeof(a)/sizeof(a[0]);//sizeof 计算字节数 通过数组的总字节数/第1个元素字节数计算数组元素个数
int ret = firstLess(a,size,3);
cout<<ret;
}
/*
输出
2
*/
4 查找第一个小于等于target值的下标
查询最后一个tartget出现的下标
查询3最后1次出现的下标

大致思路
1 每次区间缩小一半,取中间下标mid,通过中间下标对应值a[mid]和target比较,a[mid]>target 向左收缩区间(不包括a[mid]=target) 否则向右收缩
2 如果数组元素有重复的,会一直向右收缩,直到最后一个
3 最终向左收缩和向右收缩相遇在最后一个target,此时循环结束,由于条件是a[mid]>target 此时a[mid]!=target ,最后一定存在right=mid-1相等
所以返回right(left相等后进行来mid+1 返回结果不对)
#include <bits/stdc++.h>
using namespace std;
/* array查找数组 元素可能重复 size 为array数组元素个数 target待查找数字
实现使用左闭右闭区间
*/
int equalAndLess(int array[],int size,int target) {
int left=0, right =size-1;// 左右区间0 ~ size-1 总共size个元素
while (left<=right) {//边界left=right
int mid =(left+right)/2;
if (array[mid]>target){//相等不在这个分支 ,left=mid-1 后最后一定会和target相等 求最后一个,所以right符合
right=mid-1;
}else{//相等在这个分支 最后left已经符合 再进行left=mid+1最后就下标偏后一位
left=mid+1;
}
}
return right;//返回下标
}
int main(){
int a[]={0,1,2,3,3,3,3,4,5,6};//测试数据总共有9个元素 其中包括4个3是重复元素
int size=sizeof(a)/sizeof(a[0]);//sizeof 计算字节数 通过数组的总字节数/第1个元素字节数计算数组元素个数
int ret = equalAndLess(a,size,3);
cout<<ret;
}
/*
输出
6
*/
CSP初赛复习-25-二分查找-练习题
https://www.cnblogs.com/myeln/articles/17615705.html
作者:newcode 更多资源请关注纽扣编程微信公众号

从事机器人比赛、机器人等级考试、少儿scratch编程、信息学奥赛等研究学习

浙公网安备 33010602011771号