简记二分算法模板与代码案例:整数二分和浮点数二分

简介: 本文介绍了两种算法模板,分别是整数二分和浮点数二分。

一、算法模板


(1)整数二分


整数二分有两套算法模板,这两套算法模板几乎涵盖了所有二分算法的题目。


它们的主要区别在于①和②处 对 mid 的赋值不同,相应的,右边界 r 与左边界 l 的值的更新也就不同。二分首先要做的是确定边界,整数二分的本质在于边界的判断。每次都必须选择答案所在的区间进行处理。


在运用下面两套模板时,先不要管细节;找到题干中要求的性质的边界后,先套上模板即可;然后再对边界点作出考虑:如果 check() 的值为 true,边界点包括不包括在目标区间内?根据这个问题的结果,填充:


if(check()) {
    ...    //填充
}else{
    ...    //填充
}


再根据实际填充的结果,对应到下面的模板,确定 mid 的赋值处是否要加一。


// 检查x是否满足某种性质
boolean check(int 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;
        } else { 
            r = mid - 1;
        }
        
        return l;
}


(2)浮点数二分


浮点数二分与整数二分的逻辑是相同的。不过,由于浮点数的除法结果是浮点数,因此不存在边界问题,相对来说更加简单,也不用考虑mid取值加一减一的问题。


二、例题


例题:acwing-789.数的范围




解析:


这道题直接暴力是会超时的,最好的方法就是二分求解。



如果要查找起始点:



由上面的分析过程和代码模板可得如下代码:


// 二分找开始点
int l = 0, r = n-1;
while(l < r) {
    int mid = (l+r) >> 1;
 
    if(array[mid] >= k) {
        r = mid;
    }else{
        l = mid + 1;
    }
}


因为下面的步骤是 r = mid 和 l = mid + 1,所以, mid 的赋值即为 (l+r) >> 1,不用再更改为  (l+r+1) >> 1 。


然后二分查找终点



因此,得出查找终点的代码如下:


// 二分找结束点
l = 0;
r = n-1;
while(l < r) {
    int mid = (l+r+1) >> 1;
 
    if(array[mid] <= k) {
        l = mid;
    }else{
        r = mid - 1;
    }
}


题干可能不一定有解,但是二分的模板是一定有解的。二分后,通过性质,我们可以自行判断出无解的情况是什么。本题中,二分代码结束后 l 于 r 一定是相等的。此时,若 k 不等于 array[l],那么说明要查找的数不存在。


结合题干要求的输入输出格式,补充完整代码:


import java.util.Scanner;
 
 
public class Main {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        int n = reader.nextInt();   //数组长度
        int q = reader.nextInt();   //询问个数
        int[] array = new int[n];
        for (int i = 0; i < array.length; i++) {
            array[i] = reader.nextInt();
        }
 
        while(q != 0) {
            q--;
            int k = reader.nextInt();   //要查询的元素
 
            // 二分找开始点
            int l = 0, r = n-1;
            while(l < r) {
                int mid = (l+r) >> 1;
 
                if(array[mid] >= k) {
                    r = mid;
                }else{
                    l = mid + 1;
                }
            }
            //没找到
            if(array[l] != k) {
                System.out.println("-1 -1");
            }else {
                System.out.print(l + " ");
                // 二分找结束点
                l = 0;
                r = n-1;
                while(l < r) {
                    int mid = (l+r+1) >> 1;
 
                    if(array[mid] <= k) {
                        l = mid;
                    }else{
                        r = mid - 1;
                    }
                }
                System.out.println(l);
 
            }
        }
        reader.close();
    }
}


例题:数的平方根


用浮点数二分的方法,求输入一个数 x 的平方根。结果保留6位小数。




由此,可以得出代码:


import java.util.Scanner;
 
public class Main {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        double x = reader.nextDouble();
 
        double l = 0, r = x;
        while(r - l >= 1e-8) {
            double mid = (l+r)/2;
            if(mid * mid >= x) {
                r = mid;
            }else{
                l = mid;
            }
        }
        System.out.printf("%.6f", l);
        reader.close();
    }
}


注意,若题干要求结果保留6位小数,精度就设为1e-8,若题干要求保留4位小数,精度就设为1e-6

要求保留几位小数,就把精度设置的比要求的大 2 位。


例题:acwing-790.数的三次方根



首先我们要识别出,这道题可用浮点数的二分来解。


二分首先要确定边界,该题中,可以直接将数的区间范围确定为 -10000~10000。与求平方根同理:


import java.util.Scanner;
 
public class Main {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        double n = reader.nextDouble();
        double l = -10000, r = 10000;
        while(r - l >= 1e-8) {
            double mid = (l+r)/2;
            if (mid * mid * mid >= n) {
                r = mid;
            } else {
                l = mid;
            }
        }
 
        System.out.printf("%.6f", l);
        reader.close();
    }
}


数的立方根同题也在蓝桥杯中考过:蓝桥-解立方根 

相关文章
|
1月前
|
存储 分布式计算 算法
大数据-106 Spark Graph X 计算学习 案例:1图的基本计算、2连通图算法、3寻找相同的用户
大数据-106 Spark Graph X 计算学习 案例:1图的基本计算、2连通图算法、3寻找相同的用户
59 0
|
6天前
|
算法
分享一些提高二叉树遍历算法效率的代码示例
这只是简单的示例代码,实际应用中可能还需要根据具体需求进行更多的优化和处理。你可以根据自己的需求对代码进行修改和扩展。
|
17天前
|
算法 测试技术 开发者
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗;代码审查通过检查源代码发现潜在问题,提高代码质量和团队协作效率。本文介绍了一些实用的技巧和工具,帮助开发者提升开发效率。
18 3
|
16天前
|
分布式计算 Java 开发工具
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
|
23天前
|
存储 算法 搜索推荐
这些算法在实际应用中有哪些具体案例呢
【10月更文挑战第19天】这些算法在实际应用中有哪些具体案例呢
26 1
|
29天前
|
存储 缓存 算法
如何通过优化算法和代码结构来提升易语言程序的执行效率?
如何通过优化算法和代码结构来提升易语言程序的执行效率?
|
30天前
|
搜索推荐
插入排序算法的讲解和代码
【10月更文挑战第12天】插入排序是一种基础的排序算法,理解和掌握它对于学习其他排序算法以及数据结构都具有重要意义。你可以通过实际操作和分析,进一步深入了解插入排序的特点和应用场景,以便在实际编程中更好地运用它。
|
1月前
|
算法 数据可视化 新制造
Threejs路径规划_基于A*算法案例完整版
这篇文章详细介绍了如何在Three.js中完整实现基于A*算法的路径规划案例,包括网格构建、路径寻找算法的实现以及路径可视化展示等方面的内容。
59 0
Threejs路径规划_基于A*算法案例完整版
|
22天前
|
缓存 分布式计算 监控
优化算法和代码需要注意什么
【10月更文挑战第20天】优化算法和代码需要注意什么
16 0
|
1月前
|
存储 算法 机器人
Threejs路径规划_基于A*算法案例V2
这篇文章详细介绍了如何在Three.js中使用A*算法进行高效的路径规划,并通过三维物理电路的实例演示了路径计算和优化的过程。
58 0