二分查找经典例题

二分查找

请在一个有序递增数组中(不存在相同元素),采用二分查找,找出值x的位置,如果x在数组中不存在,请输出-1!

输入格式

第一行,一个整数n,代表数组元素个数(n <= 600000)

第二行,n个数,代表数组的n个递增元素(1<=数组元素值<=2000000)

第三行,一个整数x,代表要查找的数(0<=x<=2000000)

输出格式

按题意输出位置或者-1。

输入/输出例子1

输入:

10

1 3 5 7 9 11 13 15 17 19

3

输出:

2

代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,a[1000005];
int ff(int a[],int k)
{
    int l=1,r=n,m=0,bj=-1;
    while(l<=r)
    {
        m=(l+r)/2;//中间位置
        if(a[m]==k){bj=m+1;break;}
        if(a[m]>k)r=m-1;//在右半部分
        if(a[m]<k)l=m+1;//在左半部分
    }
    return  bj;
}
int main(){
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>a[i];
    cin>>k;
    cout<<ff(a,k);
    
    return 0;
}
二分查找左侧边界

请在一个有序不递减的数组中(数组中有相等的值),采用二分查找,找到值x第1次出现的位置,如果不存在x请输出-1。

请注意:本题要求出q个x,每个x在数组中第一次出现的位置。

比如有6个数,分别是:1 2 2 2 3 3,那么如果要求3个数:3 2 5,在数组中第一次出现的位置,答案是:5 2 -1。 

输入格式

第一行,一个整数n,代表数组元素个数(n <= 105)

第二行,n个整数,用空格隔开,代表数组的n个元素(1<=数组元素的值<=108)

第三行,一个整数q,代表有要求出q个数首次出现的位置(q<=105)

第四行,q个整数,用空格隔开,代表要找的数(1<=要找的数<=108)

输出格式

输出1行,含q个整数,按题意输出要找的每个数在数组中首次出现的位置,如果不存在这样的数,请输出-1。

输入/输出例子1

输入:

6

1 2 2 2 3 3

3

3 2 5

输出:

5 2 -1

代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,a[10000005],x;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    cin>>k;
    while(k--){
        scanf("%d",&x);
        int l=0,r=n+1,m=0;
        while(l+1<r)
        {
            m=(l+r)/2;
            if(a[m]<x)l=m;
            else r=m;
        }
        if(a[r]==x)printf("%d ",r);
        else printf("-1 ");
    }
    
    return 0;
}
二分查找右侧边界

请在一个有序不递减的数组中(数组中的值有相等的值),采用二分查找,找到最后1次出现值x的位置,如果不存在x请输出-1。

比如有6个数,分别是:1 2 2 2 3 3,那么如果要求3个数:3 2 5,在数组中最后一次出现的位置,答案是:6 4 -1。 

输入格式

第一行,一个整数n,代表数组元素个数(n <= 105)

第二行,n个整数,用空格隔开,代表数组的n个元素(1<=数组元素的值<=108)

第三行,一个整数q,代表有要求出q个数最后一次出现的位置(q<=105)

第四行,q个整数,用空格隔开,代表要找的数(1<=要找的数<=108)

输出格式

按题意输出位置或者-1。

输入/输出例子1

输入:

6

1 2 2 2 3 3

3

3 2 5

输出:

6 4 -1

代码:
#include<bits/stdc++.h>
using namespace std;
long long n,q,a[100005],x;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    cin>>q;
    while(q--)
    {
        scanf("%lld",&x);
        int l=1,r=n+1,mid=0;
        while(l<r)
        {
            mid=(l+r)/2;
            if(a[mid]<=x)l=mid+1;
            else r=mid;
        }
        if(a[l-1]==x) printf("%d ",l-1);
        else printf("-1 ");
    }
    return 0;
}

前面几道都是经典例题,下面我们来看看几道二分查找的实际运用

神奇的猴子(monkey)

小祖是一个爱冒险的猴子,一天它来到一个村庄,顿时,有n(1<=n<=100000)个小怪冒了出来,想把它吃了,每个小怪都有它的体力值hp(1<=hp<=maxlongint)。小祖手上有m(1<=m<=100000)个炸弹,每个炸弹威力为k(1<=k<=maxlongint),可以炸死体力小于炸弹威力所有小怪。现在它想知道,它的每一个炸弹能炸剩多少个小怪,请你编一个程序帮助它吧。 

输入格式

第一行,输入一个n,代表有n个小怪n(1<=n<=100000) 
第二行,有n个数,代表每个小怪的体力值hp(1<=hp<=maxlongint) 
第三行,输入一个m,代表有m个炸弹m(1<=m<=100000) 
接下来m行,每行一个数,代表每个炸弹威力k(1<=k<=maxlongint) 

输出格式

有m行,每行一个数代表它的每一个炸弹能炸剩多少个小怪。 

输入/输出例子1

输入:


1 2 2 2 3 



输出:



1

提示:

这道题其实就是找某个数第一次出现的位置,再用n减去这个数的位置

代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,a[10000005],x;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    cin>>k;
    while(k--){
        scanf("%d",&x);
        int l=0,r=n+1,m=0;
        while(l+1<r)
        {
            m=(l+r)/2;
            if(a[m]<x)l=m;
            else r=m;
        }
        cout<<n-r+1<<"\n";
    }
    
    return 0;
}

蓝牙连接

n个人排队签到,队伍成一条直线,签到处位置为0,第i个人与签到处的距离是pi。排队是一件无聊的事情,所以他们可以通过手机蓝牙与附近的人连接聊天,蓝牙信号的有效距离是有限的,每个人只能与他距离不超过d的人进行蓝牙连接,这样这两个人就可以聊天了。已知每个人的位置和蓝牙的有效距离d,请你编程算出有多少组可以相互聊天的人。

输入格式

第1行一个整数n。(2≤n≤1000000)

第2行一个整数d。(0≤d≤1000000)

接下来有n行,每行有一个整数pi(0≤pi≤1 000 00000),表示每一个人与签到处的距离。

输出格式

一个整数,表示队伍中有多少组可以相互聊天的人。

输入/输出例子1

输入:

5
6
1 3 5 11 34

输出:

4

样例解释

队伍中1和5,1和3,5和11,3和5一共4组人可以相互聊天。

代码:
#include<bits/stdc++.h>
using namespace std;
long long n,kk,a[1000005],ans;
int ss(long long u){//找传进来的u的位置
    long long x=1,y=n+1,mid=0;
    while(x+1<y){
        mid=(x+y)/2;
        if(a[mid]>u)y=mid;
        else x=mid;
    }
    return x;
}
int main(){
    cin>>n>>kk;
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for(int i=1;i<n;i++)
        ans+=ss(a[i]+kk)-i;
    cout<<ans;
    return 0;
}
选人

在一条坐标轴上,有N头奶牛,第i头奶牛的位置是Xi。FJ现在要选出三头奶牛去比赛,不妨假设选择了奶牛a,b,c。那么必须要满足:

1、Xa < Xb < Xc。

2、 Xb-Xa <= Xc - Xb <= 2 * (Xb - Xa)。

你的任务是计算,FJ总共有多少种不同的选择?

输入格式

第一行,一个整数N。 3 <= N <= 1000。 接下来有N行,第i行是整数Xi。

输出格式

一个整数。

输入/输出例子1

输入:

5 
3 
1 
10 
7 
4

输出:

4

样例解释

可以有4种不同的选择,每种选择对应的3头奶牛的坐标是: {1,3,7} {1,4,7} {4,7,10} {1,4,10}

代码:
#include<bits/stdc++.h>
using namespace std;
long long n,s,q[10000000],t,m,ans,ans2,l,r;
int main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&q[i]);
    sort(q+1,q+1+n);
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            int l=0,r=n+1,m;
            while(l+1<r)
            {
                m=(l+r)/2;
                if(q[j]-q[i]>q[m]-q[j])l=m;//符合条件
                else r=m;
            }
            ans=l;
            l=0,r=n+1;
            while(l+1<r)
            {
                m=(l+r)/2;
                if(q[m]-q[j]>2*(q[j]-q[i]))r=m;//符合条件
                else l=m;
            }
            ans2=l;
            t+=ans2-ans;
        }
    }
    cout<<t;
    return 0;
}
天堂_珍珠

我有很多很多(n条)用魔法合成的珍珠项链……(其实神仙比凡人更爱美),每天起来我都要从中挑一条戴上……挑哪条很有讲究,如果比情敌的难看,那么就会被(--),如果比天后Hera的好看,那么就完蛋了(--)。所以我希望你能帮帮我,解决这个令人头疼的问题——每天帮我算算,那天我能戴的项链有多少条。

输入格式

第一行为正整数n(项链总条数)。

第二行有n个整数(代表每条项链晶的好看程度Xi,0<=Xi<=maxlongint。)

第三行为正整数m,表示总天数(也就是总询问次数)。

以下m行,每行两个整数Ai,Bi(1<=Ai,Bi<=maxlongint),询问好看程度在Ai到Bi之间的项链条数(含等于Ai或Bi的,Ai与Bi大小关系不确定)。

输出格式

输出m行,对于每次询问输出一行,从Ai到Bi(含Ai,Bi)好看程度在Ai到Bi之间的项链条数。

输入/输出例子1

输入:

7 
8 2 3 5 6 7 7 
6 
1 5 
8 6 
1 10 
5 5 
4 4 
7 8

输出:

3 
4 
7 
1 
0 
3

数据范围:对于25%数据,有m,n<=1000。 对于100%数据,有m,n<=100000。

代码:
#include<bits/stdc++.h>
using namespace std;
long long n,m,a[100005],l,r;
long long sa(long long u)
{
    long long x=0,y=n+1,mid=0;
    while(x+1<y)
    {
        mid=(x+y)/2;
        if(a[mid]>=u)y=mid;
        else x=mid;
    }
    return y;
}
int main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    scanf("%lld",&m);
    sort(a+1,a+n+1);
    for(int i=1;i<=m;i++)
    {
        scanf("%lld%lld",&l,&r);
        if(l>r)swap(l,r);
        printf("%lld\n",sa(r+1)-sa(l));
    }
    return 0;
}

菜鸟代码,大佬勿喷......

  • 22
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在C语言中,二分法查找是一种高效的查找算法。下面是一个示例程序: ```c #include <stdio.h> int binarySearch(int arr[], int left, int right, int key) { while (left <= right) { int mid = (left + right) / 2; if (arr[mid == key) { return mid; } else if (arr[mid < key) { left = mid + 1; } else { right = mid - 1; } } return -1; } int main() { int arr[] = {1, 9, 13, 23, 70, 73, 74, 77, 79, 80, 84, 89, 94, 99, 101}; int n; printf("请输入一个数字:"); scanf("%d", &n); int index = binarySearch(arr, 0, sizeof(arr) / sizeof(arr<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [c程序设计习题参考(谭浩强三版)习题参考解答](https://download.csdn.net/download/wmxnzn/2656246)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [C语言经典100题——用二分法在一个有序数组中查找某个数字](https://blog.csdn.net/yahid/article/details/123389973)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [详解【C语言】中的二分查找法和折半查找法(例题解答)](https://blog.csdn.net/m0_63325890/article/details/120993495)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值