AcWing算法基础课-二分

本文深入讲解了二分法的本质及应用场景,介绍了两种不同的二分模板及其适用情况,并通过实例演示了如何利用二分法解决实际问题。

二分

二分本质是用来查找满足某种性质的边界点
在给定区间内,能找到某种性质(check函数):

使得区间分为两部分
一部分满足,另外一部分不满足这种性质。

二分可以用来寻找这个性质的边界:满足某种性质的第一个元素;或者是满足某种性质的最后一个元素。
从而有两个不同模板

注意二分法一定能找到满足某种性质的边界点,但它不一定是你要找的目标,目标一不定在区间内,先写check函数,根据check函数更新区间,再判断用哪个模板。

二分模板一共有两个,分别适用于不同情况。
算法思路:
假设目标在闭区间[l,r]中,每次将区间长度缩小一半,当l=r时,我们就找到了目标值。
版本1

当我们将区间[l, r]划分成[l, mid]和[mid + 1, r]时,其更新操作是r = mid或者l = mid +1;,计算mid时不需要加1。

int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}

版本2

当我们将区间[l, r]划分成[l, mid - 1]和[mid, r]时,其更新操作是r = mid - 1或者l =mid;,此时为了防止死循环,计算mid时需要加1。

int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

AcWing 789.数的范围

在这里插入图片描述

#include<iostream>
using namespace std;
const int N=1e5+10;
int q[N];
int n,m;

int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
        cin>>q[i];
    while(m--)
    {
        int k;
        cin>>k;
        int l=0,r=n-1;
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(q[mid]>=k)
                r=mid;
            else
                l=mid+1;
        }
        if(q[l]!=k)
            cout<<-1<<' '<<-1<<endl;
        else
        {
            cout<<l<<' ';
            int l=0,r=n-1;
            while(l<r)
            {
                int mid=(l+r+1)>>1;
                if(q[mid]<=k)
                    l=mid;
                else
                    r=mid-1;
            }
            cout<<l<<' '<<endl;
        }
        
    }
    return 0;
}

AcWing 790.数的三次方根

在这里插入图片描述

#include<iostream>
using namespace std;
int main()
{
    double x;
    cin>>x;
    double l=-100,r=100;//根据题目范围 开三次方根 估计答案大概范围
    while(r-l>1e-8)
    {
        double mid=(l+r)/2;
        if(mid*mid*mid>=x)
            r=mid;
        else
            l=mid;
    }
    printf("%.6lf\n",l);
    return 0;
}

浮点数的平方根

#include<iostream>
using namespace std;
int main()
{
    double x;
    cin>>x;
    double l=0,r;
    //一个浮点数开平方,答案绝对值一定大于等于0,但是右边界根据输入浮点数是否大于1确定
    if(x>1)
        r=x;
    else
        r=1;
    while(r-l>1e-8)//经验: 保留6位小数 1e-8 4位 1e-6 多2
    {
        double mid=(l+r)/2;
        if(mid*mid>=x) r=mid;
        else l=mid;
    }
    printf("%.6lf\n",l);
    return 0;
}
### AcWing 算法基础课中的二分法相关练习题 #### 二分查找基本概念 二分查找是一种高效的搜索算法,适用于已排序的数据结构。其核心思想是在每次迭代中将搜索范围减半,从而快速定位目标值的位置[^1]。 #### 练习题推荐 ##### 查找特定元素 对于给定的一个升序数组`nums`以及一个整数值`target`,编写函数来实现二分查找返回该值首次出现位置;如果不存在则返回-1。 ```python def binary_search(nums, target): left, right = 0, len(nums) - 1 while left <= right: mid = (left + right) // 2 if nums[mid] == target and (mid == 0 or nums[mid - 1] != target): return mid elif nums[mid] >= target: right = mid - 1 else: left = mid + 1 return -1 ``` ##### 寻找峰值元素 在一个无重复元素的数组里找到任意一个满足条件`A[i]>A[i−1] && A[i]>A[i+1]` 的索引i作为峰顶并输出它; 如果有多个这样的点只需给出其中一个即可. ```cpp int findPeakElement(vector<int>& nums) { int n=nums.size(); if(n==1 || nums[0]>nums[1])return 0; if(nums[n-1]>nums[n-2])return n-1; int l=1,r=n-2; while(l<=r){ int m=(l+r)/2; if((m==n-1||nums[m]>nums[m+1])&&(m==0||nums[m]>nums[m-1]))return m; else if(m>0&&nums[m]<nums[m-1]) r=m-1; else l=m+1; } } ``` ##### 计算平方根 计算并返回非负实数x的小数部分最接近于y的那个数z(保留k位有效数字),其中y=x^(1/2). ```c++ double mySqrt(double x,int k) { double L = 0,R = max(1.0,x); for(int i=0;i<k;++i){ double M =(L+R)*0.5; if(M*M>x) R=M-(pow(10,-i)); else L=M+(pow(10,-i)); } return round(L*(pow(10,k)))/(pow(10,k)); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值