二分算法

 

目录

          0、二分法简介

1、二分入门-洛谷P1024一元三次方程求解

2、Java快速输入+二分查找 P2249查找

3、二分查找- 洛谷P1678 烦恼的高考志愿

4、二分答案+java快速输入 洛谷P1873 砍树

0 、二分法简介

  • 简介

二分查找(英语:binary search),也称折半搜索(英语:half-interval search)、对数搜索(英语:logarithmic search),是用来在一个有序数组中查找某一元素的算法。

  • 工作原理

以在一个升序数组中查找一个数为例。

它每次考察数组当前部分的中间元素,如果中间元素刚好是要找的,就结束搜索过程;如果中间元素小于所查找的值,那么左侧的只会更小,不会有所查找的元素,只需到右侧查找;如果中间元素大于所查找的值同理,只需到左侧查找。

  • 性质

时间复杂度

二分查找的最优时间复杂度为O(1) 。

二分查找的平均时间复杂度和最坏时间复杂度均为 O(logn)。因为在二分搜索过程中,算法每次都把查询的区间减半,所以对于一个长度为n 的数组,至多会进行 O(logn) 次查找。

空间复杂度

迭代版本的二分查找的空间复杂度为O(1) 。

递归(无尾调用消除)版本的二分查找的空间复杂度为O(logn) 。

  • 应用
  1. 二分查找
  2. 二分答案
  3. 二分法通常可以和其他算法一起考察,通常都成为其它算法的载体。
  4. 难度范围非常广,下至 NOIp 第一题,上至 NOI/ICPC World Final 压轴题
  5. 二分法应用十分广泛,很多其他算法都有间接用到二分算法的情况。
  • 二分查找思路

二分查找是一种在有序数组中查找某一特定元素的查找算法。
查找过程从数组的中间元素开始:如果中间元素正好是要查找的元素,则查找过程结束;
如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。
如果在某一步骤数组为空,则代表找不到。
「连续」「单调」「确切答案」 解通常是唯一的,或者不存在。

数组a二分查找某元素的模板: 

 static int find(int x) {
     int l=1,r=n;
     while(l
  • 二分答案

二分答案,即通过题目中包含的单调性对答案进行二分。大多数二分答案可以看做是标准二分法套了一个奇奇怪怪的函数。 解答需要使用二分答案的题目,最重要的是观察出单调性。

通常来说,二分答案题目为下列两种中的一种:给定一个评价函数,求评价函数的最小值 / 最大值 。给定一个条件,要求在满足条件的同时,使得代价最小。计算函数或者判断符合条件需要消耗极长的时间;或者评价函数的值域太大了,不能一 一计算。

二分算法_第1张图片

1、二分入门-洛谷P1024一元三次方程求解

oj:https://www.luogu.com.cn/problem/P1024  标签:数论,数学,二分答案,枚举,暴力,分治,NOIp提高组2001(或之前)

二分算法_第2张图片

思路:二分算法_第3张图片

package 二分查找与二分答案;

import java.util.Scanner;

public class P1024一元三次方程求解 {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		double a=in.nextDouble();
		double b=in.nextDouble();
		double c=in.nextDouble();
		double d=in.nextDouble();
		double y1,y2,j;
		for(double i=-100;i<=100;i+=0.001) {
			j=i+0.001;	//j取到保留的小数位下一位
			y1=a*i*i*i+b*i*i+c*i+d;
			y2=a*j*j*j+b*j*j+c*j+d;
			if(y1*y2<=0)//y1,y2异号或其一为0
				System.out.printf("%.2f ",(i+j)/2);
		}
	}
}

2、Java快速输入+二分查找 P2249查找

oj:https://www.luogu.com.cn/problem/P2249   标签:二分答案

二分算法_第4张图片

package 二分查找与二分答案;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class P2249查找 {
	static int[] a;
	static int n;
	public static void main(String[] args) throws IOException {
		StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
		PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
		in.nextToken();
		n=(int)in.nval;//相当于int n = in.nextInt();
		in.nextToken();
		int m=(int)in.nval;
		a=new int [n+1];
		int[] b=new int [m+1];
		a[0]=-1;//有可能会要查找等于0的数,所以我们把第一个改成-1
		for(int i=1;i<=n;i++) {
			in.nextToken();
			a[i]=(int)in.nval;
		}
		for(int i=1;i<=m;i++) {
			in.nextToken();
			b[i]=(int)in.nval;
			out.print(find(b[i])+" ");
		}
		out.flush();
	}
	static int find(int x) {//参数的数目直接影响调用函数的速度,参数越多,调用函数就越慢.这题如果函数是两个参数,就会超时。
		int l=1,r=n;
		while(l=x)r=mid;// 如果中间值大于等于目标值就继续往左边找
			else l=mid+1;
		}
		if(a[l]==x)return l;
		else return -1;
	}
}

java快速输入输出用法见:https://blog.csdn.net/qq_44491991/article/details/115186693

3、二分查找- 洛谷P1678 烦恼的高考志愿

OJ:https://www.luogu.com.cn/problem/P1678 标签:模拟,贪心,排序,二分查找,高性能

二分算法_第5张图片

package 二分查找与二分答案;

import java.util.Arrays;
import java.util.Scanner;

public class P1678烦恼的高考志愿 {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int m=in.nextInt();
		int n=in.nextInt();
		int[] a=new int[m];
		int[] b=new int[n];
		for(int i=0;i=a[mid])l=mid;
				else r=mid;
			}
			ans+=Math.min(Math.abs(a[l]-b[i]),Math.abs(a[r]-b[i]));//加上两个绝对值中最小
		}
		System.out.println(ans);
	}
}

4、二分答案+java快速输入 洛谷P1873 砍树

oj:https://www.luogu.com.cn/problem/P1873 标签:二分答案,高性能

二分算法_第6张图片


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class Main {
	public static void main(String[] args) throws IOException {
		StreamTokenizer  in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
		PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
		in.nextToken();
		int n=(int)in.nval;
		in.nextToken();
		int m=(int)in.nval;
		int[] a=new int[n];
		int l=0,r=0;
		for(int i=0;ix)sum+=a[i]-x;
//		}
//		return sum>=m;
		int sum = 0;
		for(int i = 0;i < a.length;i++) {
			if(a[i] > x) {
				sum += (a[i] - x);
				if(sum >= m)return true;//只要满足需求即可返回了!防止sum超范围。
			}
		}
		return false;
	}
}

未完待续。。。

你可能感兴趣的:(算法专项,二分法,算法,洛谷,二分答案,二分查找)