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

简介: 1.整数二分>### 二分本质>- 有单调性,一定可以二分>- 二分的题目,不一定非要有单调性>### 思路:分俩种情况,有俩种模板

1.整数二分

二分本质

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

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

1661149299357.png

1661149312078.png

具体考虑用哪一个模板:

  • 碰到二分题,写完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
<br/>
输入格式
第一行包含整数 n 和 q,表示数组长度和询问个数。

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

接下来 q 行,每行包含一个整数 k,表示一个询问元素。
<br/>
输出格式
共 q 行,每行包含两个整数,表示所求元素的起始位置和终止位置。

如果数组中不存在该元素,则返回 -1 -1。
<br/>
数据范围
1 ≤ n ≤ 100000
1 ≤ q ≤ 10000
1 ≤ k ≤ 10000
<br/>
输入样例:

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;
}
目录
相关文章
|
19天前
求一个整数的所有因数
【10月更文挑战第25天】求一个整数的所有因数。
13 5
|
1月前
两个整数相加
【10月更文挑战第12天】两个整数相加
19 5
|
1月前
取一个整数a从右端开始的 4~7 位
取一个整数a从右端开始的 4~7 位。
21 7
|
2月前
比较三个整数大小
比较三个整数大小
49 13
|
2月前
|
存储 编译器 C语言
取一个整数a从右端开始的4~7位。
取一个整数a从右端开始的4~7位。
27 1
|
6月前
63.取一个整数a从右端开始的4~7位。
63.取一个整数a从右端开始的4~7位。
34 0
|
5月前
取一个整数 a 从右端开始的 4~7 位
【6月更文挑战第23天】取一个整数 a 从右端开始的 4~7 位。
43 9
【剑指offer】-数值的整数次方-12/67
【剑指offer】-数值的整数次方-12/67
wustojc1006求2个整数的和
wustojc1006求2个整数的和
39 0
剑指offer 15. 数值的整数次方
剑指offer 15. 数值的整数次方
52 0