二分小细节的问题+STL中的二分函数

本文详细介绍了二分查找算法在整型和浮点型数据上的应用,以及C++中lower_bound和upper_bound函数的原理和用法,展示了如何在有序序列中高效查找。同时提到了C++11中的auto关键字在简化代码中的作用。
摘要由CSDN通过智能技术生成

二分法:

时间复杂度:o(logn)

空间复杂度:o(1);

用二分法的条件:(1)数列是有界的;(2)数列具有单调性

二分法的模板:整型2种,浮点型1种;

整型:

13578

找出3的下标:

当a[mid]<=num时,我们要在mid右边的区间里查找目标值,可是在mid这一点是有可能等于目标值num的,所以我们的l=mid,else  r=mid-1;为了防止陷入死循环(假如l=4,r=5,(l+r)/2=4;),所以再次循环时mid=(l+r+1)/2;

#include <iostream>
using namespace std;
int a[100];
int main(){
    int n,num;
    cin>>n>>num;

    for(int i=1;i<=n;i++){
        cin>>a[i];
    }

    int l=1,r=n;
    while(l<r){
        int mid=(l+r+1)/2;
        if(a[mid]<=num){
            l=mid;
        }else{
            r=mid-1;
        }
    }

    if(a[r]==num){
        cout<<r<<endl;
    }else{
        cout<<"-1"<<endl;
    }
    return 0;
}

当a[mid]>=num时,我们要在mid左半边的区间里查找目标值num,因为右半边不包含我们的目标值,但在mid这一点是有可能等于num的,所以r=mid,else l=mid+1;

#include <iostream>
using namespace std;
int a[100];
int main(){
    int n,num;
    cin>>n>>num;

    for(int i=1;i<=n;i++){
        cin>>a[i];
    }

    int l=1,r=n;
    while(l<r){
        int mid=(l+r)/2;
        if(a[mid]>=num){
            r=mid;
        }else{
            l=mid+1;
        }
    }

    if(a[r]==num){
        cout<<r<<endl;
    }else{
        cout<<"-1"<<endl;
    }
    return 0;
}

浮点型:主要考虑精度的问题,只有一种写法

例1:

#include <iostream>
#include<algorithm>
#include<iomanip>
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
int n,m,c,i,j,t;
bool check(double k){
    double sum=0,v=1;
    for(j=1;j<=c;j++){
       v*=(1+k);
       sum+=(m/v);
    }
    return sum>=n;
}
int main(){
    IOS;
    cin>>n>>m>>c;

    double l=0,r=20;
    while(l+0.0001<r){
         double mid=(l+r)/2;//这一步不可以用'>>',
        if(check(mid)){//在 C++ 中,位运算符 >> 用于将一个整数的二进制表示向右移动指定的位数。
           l=mid;          //当对浮点数进行位运算时,编译器会将浮点数转换为整数,然后执行位运算
                            //因此,对浮点数进行位运算通常会导致不可预期的结果,因为浮点数的二进制表示通常不代表它的实际值。
        }else{
            r=mid;
        }
    }

    cout<<fixed<<setprecision(1)<<l*100<<endl;
    return 0;
}

例二:

#include <iostream>
#include<algorithm>
#include<iomanip>
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
int n,m,i,j;
double a[11000];
bool check(double k){
    int sum=0;
    for(j=1;j<=n;j++){
       sum+=(a[j]/k);
    }
    return sum>=m;
}
int main(){
    IOS;
    cin>>n>>m;

    double sum=0.0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        sum=max(sum,a[i]);
    }

    double l=0.0,r=sum;
    while(r-l>1e-6){
        double mid=(l+r)/2;
        if(check(mid)){
            l=mid;
        }else{
            r=mid;
        }
    }

    cout<<l<<endl;//cout默认情况下输出浮点型小数时
                  //保留六位有效数字
    return 0;
}

关于STL中的lower_bound和upper_bound :

1>>它俩的本质也是二分

2>>是在有序数列中进行查找的函数

(有序序列是指其中的元素按照某种规则或者特定的顺序排列的序列)

lower_bound:

返回在一个范围[first,last]中第一个大于或等于给定值的迭代器 

upper_bound:

返回第一个大于给定值的迭代器

lower_bound和upper_bound 的相同点

 如果给定值不存在,则返回第一个大于该值元素的迭代器

如果所有元素都小于给定值,则返回末尾元素的迭代器

关于lower_bound的实例:

    如果是vector:
       

 vector<int> vec = {1, 2, 3, 3, 5, 7, 9};
            auto lb = lower_bound(vec.begin(), vec.end(), 3);


    如果是set:
       

 set<int> mySet = {1, 2, 3, 5, 7, 9};
            auto it = mySet.lower_bound(3);


    如果是map:
       

 map<int, string> myMap = {{1, "one"}, {2, "two"}, {3, "three"}, {5, "five"}, {7, "seven"}};
               auto it = myMap.lower_bound(3);


    如果是arr[]数组,里面有n个元素:
       

 int  it = lower_bound(arr, arr + n, 3)-arr;

当lower_bound和upper_bound相减时,得到的值是有多少个相同的给定值:
   

auto lower1 = distance(vec.begin(),lower_bound(vec.begin(), vec.end(), 3));
    auto upper1 = distance(vec.begin(),upper_bound(vec.begin(), vec.end(), 3));

    // 计算范围内元素的个数

    cout<<upper1-lower1<<endl;

auto:

 是 C++11 引入的关键字,用于自动推导变量的类型。使用 auto 关键字声明变量时,编译器会根据变量的初始化表达式推断出其类型,并将其替换为实际类型。这样做的好处是可以简化代码,特别是在处理模板和迭代器等复杂类型时。

auto x = 5; // x的类型将会是int
auto y = 3.14; // y的类型将会是double
vector<int> vec = {1, 2, 3, 4, 5};
auto it = vec.begin(); // it的类型将会是vector<int>iterator

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值