【3.整数与浮点数二分】

1.整数二分

二分本质

  • 有单调性,一定可以二分
  • 二分的题目,不一定非要有单调性

思路:分俩种情况,有俩种模板

在这里插入图片描述
在这里插入图片描述

具体考虑用哪一个模板:

  • 碰到二分题,写完mid 之后,先写check函数
  • 根据check(mid)想一下,true 和false该怎么更新区间
  • 如果更新区间是 l = mid ,r = mid + 1 ,此时使用mid = (l + r + 1) / 2
  • 如果更新区间是 r = mid, l = mid + 1, 此时使用mid = (l + r) / 2
    如果在第一种情况下,l = r - 1,因为是除法是向下取整,所以mid = l ,此时更新区间还是[ l , r]死循环。

题目

给定一个按照升序排列的长度为 n 的整数数组,以及 q个查询。

对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0 开始计数)。

如果数组中不存在该元素,则返回 -1 -1


输入格式
第一行包含整数 n 和 q,表示数组长度和询问个数。

第二行包含 n 个整数(均在 1∼10000 范围内),表示完整数组。

接下来 q 行,每行包含一个整数 k,表示一个询问元素。


输出格式
共 q 行,每行包含两个整数,表示所求元素的起始位置和终止位置。

如果数组中不存在该元素,则返回 -1 -1。


数据范围
1 ≤ n ≤ 100000
1 ≤ q ≤ 10000
1 ≤ k ≤ 10000


输入样例:

6 3
1 2 2 3 3 4
3
4
5

输出样例

3 4
5 5
-1 -1

代码

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

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i ++) scanf("%d", &q[i]);
  
    while (m --)
    {
        int x;
        scanf("%d", &x);
       
        int l = 0, r = n - 1;
       
        while(l < r)
        {
           int mid = (l + r) >> 1;
           if (q[mid] >= x) r = mid;
           else l = mid + 1;
         
        }
        if (q[l] != x) 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] <= x) l = mid;
               else r = mid - 1;
           }
           cout << l << endl;
       }
   }
   return 0;
}

2.浮点数二分

  • 浮点数二分,每次都会严格缩小一半,不用处理边界问题
  • 而整数二分,因为有整数的存在,所以缩小不一定是一半,需要处理边界问题

思路:

  • 与整数二分一样,只不过当r - l <= 1e6(非常小的数),此时就不需要进行二分了

代码

求根号X的值


#include <iostream>
using namespace std;

int main()
{
    double x;
    cin >> x;
    
    double l = 0, r = x;
    while (r- l > 1e-8)
    {
        double mid = (l + r) / 2;
        
        if (mid * mid >= x) r = mid;
        else l = mid;
    }
    printf("%lf", l);
    return 0;
}

3.附加模板

整数二分

bool check(double x){/* */}       //检查x是否满足某种性质
//区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用;
int bsearch_1(int l, int r)
{
   while (l < r)
   {
		int mid = l + r >> 1;
       if(check(mid)) r = mid;  //check()判断mid是否满足性质
       else l = mid + 1;
	}
   return l;
}



//区间[l, r]被划分成[l, mid - 1]和[mid , r]时使用;
int bsearch_2(int l, int r)
{
   while (l < r)
   {
		int mid = l + r + 1 >> 1;
       if(check(mid)) l = mid;  //check()判断mid是否满足性质
       else r = mid - 1;
	}
   return l;
}

浮点数模板

bool check(double x){/* */}       //检查x是否满足某种性质
double bsearch_3(double l, double r)
{
   while (l < r)
   {
		double mid = l + r >> 1;
       if(check(mid)) l = mid;  //check()判断mid是否满足性质
       else r = mid ;
	}
   return l;
}
  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小呆鸟_coding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值