【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
    评论
好的,我会为你解答关于编译原理课程设计的问题。首先,让我们来了解下编译原理的基本概念。 编译原理是指翻译高级语言程序的一门学科,它主要研究如何将高级语言程序翻译成机器语言程序。编译原理的主要任务是设计和实现编译器。 针对你的问题,我们来分步骤地回答: 第一步:环境部署 首先,我们需要安装一些必要的工具,例如编译器、文本编辑器等。在这里,我们可以选择使用C++语言来实现计算器,因为C++语言是一种高效、灵活的编程语言,可以很好地满足我们的需求。 在安装好必要的工具之后,我们需要编写一些基本的代码,例如定义数据类型、变量、函数等。 第二步:需求分析 在这个阶段,我们需要明确计算器的功能和要求,例如支持加减乘除和括号,能够处理整数浮点数等。 我们还需要确定计算器的界面设计和交互方式,例如通过命令行界面或者图形界面来输入和输出计算结果。 第三步:总体设计 在这个阶段,我们需要根据需求分析的结果,设计计算器的总体结构和算法,例如如何处理加减乘除和括号等运算符,如何处理整数浮点数等数据类型。 我们还需要考虑如何进行错误处理,例如输入非法字符或者除数为0等错误情况。 第四步:详细设计与实现 在这个阶段,我们需要根据总体设计的结果,进行详细的代码设计和实现。具体来说,我们可以采用词法分析、语法分析和语义分析等技术来实现计算器的编译器。 词法分析可以将输入的字符串分解成符号序列,例如将“2+3*4”分解成“2”、“+”、“3”、“*”、“4”等符号。 语法分析可以根据语法规则构建语法树,例如将“2+3*4”构建成一个二叉树,其中根节点为“+”,左子树为“2”,右子树为“3*4”。 语义分析可以对语法树进行计算,例如对“2+3*4”的语法树进行计算得到14。 最后,我们需要对代码进行测试和调试,确保计算器能够正确地处理各种输入情况,并且能够输出正确的计算结果。 以上就是编译原理课程设计一个简单的计算器的基本流程,希望能够对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小呆鸟_coding

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

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

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

打赏作者

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

抵扣说明:

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

余额充值