Acwing 数的范围-二分算法-java实现

二分算法

二分算法分为整数二分和浮点数二分 浮点数二分比较容易
二分的本质不是单调性 有单调性的一定可以二分 但是能二分的不一定非得有单调性
但是二分查找需要有序性


一、原题链接

给定一个按照升序排列的长度为 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

二、题解

算法分析

二分法的模板

二分算法的解释

二分算法分为两个边界 一个是 <= x 一个是>=x 的也就是上面图中的红色区域和绿色区域(为了书写区分 l = L)

红色区域

这时候mid 为图中 1 的情况 mid在红色区域 要想包含解x 则l = mid
else mid跑到绿色区域 要想包含解的话 r = mid-1;
注意: 此时的Mid = l+r +1 >> 1;
为什么是加1 呢 ? 这是因为 / 是向下取整的 如果在[mid,r]中 l = r-1 的话
这时候 mid = l + r >> 1 = L (因为是向下取整的) 那L = mid 这时候就陷入了死循环 所以要加1

	mid=(l+r+1)/2		//注意这个+1,不然会出现死循环,例如l与r只差1,且check(mid)==true会出现死循环if(check(mid)){		//check(mid)作用是判断mid是否满足红颜色的性质
		//边界点在[mid,r]之间,更新方式,l=mid
​	}else{
    	//边界点在[l,mid-1]之间,更新方式,r = mid-1
	}

绿色区域

这时候mid 为图中 2的情况 mid在绿色区域 要想包含解x 则r = mid
else mid跑到红色区域 要想包含解的话 l = mid+1;
注意: 此时的Mid = l+r >> 1;

	mid = (l+r)/2if(check(mid)){	//check(mid)作用是判断mid是否满足绿颜色的性质,如果满足,那么绿颜色的边界点一定在[l,mid]之间
    	//边界点在[l,mid]之间,更新方式为r=mid
	}else{
    	//边界点在[mid+1,r]之间,更新方式为l = mid+1
	}

代码如下(示例):

import java.io.*;
import java.util.*;

public class Main {
    static final int N = 100010;
    static int[] a = new int[N];

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String[] s1 = in.readLine().split(" ");
        int n = Integer.parseInt(s1[0]);
        int q = Integer.parseInt(s1[1]);
        String[] s2 = in.readLine().split(" ");
        for(int i = 0; i < n; i ++) a[i] = Integer.parseInt(s2[i]);

        while(q -- > 0) {
            int k = Integer.parseInt(in.readLine());
            int l = 0, r = n - 1;
            while(l < r) {
                int mid = l + r >> 1;
                if(a[mid] >= k) r = mid;
                else l = mid + 1;
            }
            if(a[l] != k) System.out.println("-1 -1");
            else {
                int left = l;//此时l = r  所以left = l 或者r 都可以 哪个都行
                //System.out.println(l+" " );   后面在输出l
                l = 0;
                r = n - 1;
                while(l < r) {
                    int mid = l + r + 1 >> 1;
                    if(a[mid] <= k) l = mid;
                    else r = mid -1;
                }
                System.out.println(left + " " + l);
            }
        }
    }
}

 

C++ 代码模板如下(来自y总的模板)

 bool check(int 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;
        else r = mid - 1;
    }
    return l;
}

 

浮点二分- 数的三次方根

这个简单就不用写那么多考虑条件

给定一个浮点数 n,求它的三次方根。

输入格式
共一行,包含一个浮点数 n。

输出格式
共一行,包含一个浮点数,表示问题的解。

注意,结果保留 6 位小数。

数据范围
−10000≤n≤10000
输入样例:
1000.00
输出样例:
10.000000

直接代码模板

 bool check(double x) {/* ... */} // 检查x是否满足某种性质

double bsearch_3(double l, double r)
{
    const double eps = 1e-6;   // eps 表示精度,取决于题目对精度的要求
    while (r - l > eps)
    {
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;
    }
    return l;
}

这里面的a,b要根据具体二分的范围来指定,对于eps的值,如果题目中要求保留4位小数,eps取1e-6,如果题目中要求保留6位小数,那eps取1e-8

import java.io.*;

class Main{

    public static void main(String[]args)throws IOException{
        BufferedReader input=new BufferedReader(new InputStreamReader(System.in));
        double n=Double.parseDouble(input.readLine());

        double l=-1000;
        double r=1000;
        while(r-l>1e-8){
            double mid=(l+r)/2;
            if(mid*mid*mid >= n) r=mid;//绿色区域
            else l=mid;
        }

        System.out.printf("%.6f\n",l);
    }
}

 
posted @   依嘫  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示