洛谷题单:【算法1-6】二分查找与二分答案

(1)P2249 【深基13.例1】查找
这道题本身并不难,典型的一个二分查找,用java自带的二分查找函数就可以实现.但是这题存在多个值相同的情况,根据例题我们知道,返回的是第一个数字。但如果直接用二分搜索肯定不能保障搜索到的是第一个,那么 我们就要自己手写一个二分查找,并且当找到了元素后再判断一下是不是第一个,如果不是我们就往前移。

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

public class Main {
	public static void main(String[] args) throws IOException {
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		PrintWriter out=new PrintWriter(System.out);
		String[] s=br.readLine().split(" ");
		int n=Integer.valueOf(s[0]),m=Integer.valueOf(s[1]);
		int[] arr=new int[n+1];
		s=br.readLine().split(" ");
		for(int i=1;i<=n;i++) {
			arr[i]=Integer.valueOf(s[i-1]);
		}
		s=br.readLine().split(" ");
		for(int i=0;i<m;i++) {
			out.print(binarySearch(1, n, arr, Integer.valueOf(s[i]))+" ");
		}
		out.close();
	}
	static int binarySearch(int l,int r,int[] arr,int k) {
		int res=-1;
		while(l<=r) {
			int m=(l+r)/2;
			if(arr[m]==k) {
				res=m;
				break;
			}
			else if(arr[m]>k) {
				r=m-1;
			}
			else if(arr[m]<k) {
				l=m+1;
			}
		}
		if(res!=-1) {
			while(arr[res-1]==k&&res!=1) {
				res--;
			}
		}
		return res;
	}
}

(2)P1102 A-B 数对
这道题有一个非常巧妙的方法,利用Map集合,首先遍历一遍数组,将各个数字和它出现的次数用map存储起来。然后将数组中每个元素减c。最后再遍历一遍数组,把数字中每个元素出现的次数累加起来。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;

public class Main {
	public static void main(String[] args) throws IOException {
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		String[] s=br.readLine().split(" ");
		int n=Integer.valueOf(s[0]),m=Integer.valueOf(s[1]);
		HashMap<Integer, Integer> hs=new HashMap<Integer, Integer>();
		int[] arr=new int[n];
		s=br.readLine().split(" ");
		for(int i=0;i<n;i++) {
			arr[i]=Integer.valueOf(s[i]);
			if(hs.containsKey(arr[i])) {
				hs.put(arr[i], hs.get(arr[i])+1);
			}
			else {
				hs.put(arr[i], 1);
			}
			arr[i]-=m;
		}
		long sum=0;
		for(int i=0;i<n;i++) {
			if(hs.containsKey(arr[i]))
				sum+=hs.get(arr[i]);
		}
		System.out.println(sum);
	}
}

(3)P1873 砍树
一道二分答案题目,像这种题目一般都是有一个模板的。用二分来选取一个砍树的高度,然后写个函数判断这个长度是否满足条件,如果满足,则在更高的长度进行选取,不满足则在低的长度选取。
ps:这题有一个点用java做会超内存。。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
	static int[] arr;
	public static void main(String[] args) throws IOException {
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		String[] s=br.readLine().split(" ");
		int n=Integer.valueOf(s[0]),m=Integer.valueOf(s[1]);
		arr=new int[n];
		s=br.readLine().split(" ");
		for(int i=0;i<n;i++) {
			arr[i]=Integer.valueOf(s[i]);
		}
		int l=1,r=1000000000;
		int max=0;
		while(l<=r) {
			int mid=(l+r)/2;
			if(judge(mid,m)) {
				max=mid;
				l=mid+1;
			}
			else {
				r=mid-1;
			}
		}
		System.out.println(max);
	}
	public static boolean judge(int mid,int k) {
		int sum=0;
		for(int i=0;i<arr.length;i++) {
			if(arr[i]>mid) {
				sum+=arr[i]-mid;
			}
			if(sum>=k) {
				return true;
			}
		}
		return false;
	}
}

(4)P1024 一元三次方程求解
首先,解的范围是-100到100,而且每个解绝对值差大于1,那么可以枚举每个区间,每个区间的大小为1。然后把区间端点带入方程,如果左端点为0,直接输出左端点。否则用二分的思想,在区间内寻找解,因为要满足f(x1)*f(x2)<0才可能有解

import java.util.Scanner;

public class Main {
	static double a,b,c,d;
	public static double f(double x) {
		return a*x*x*x+b*x*x+c*x+d;
	}
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		a=sc.nextDouble();b=sc.nextDouble();c=sc.nextDouble();d=sc.nextDouble();
		double l,r;
		for(int i=-100;i<100;i++) {
			l=i;r=i+1;
			double f1=f(l);
			double f2=f(r);
			if(f1==0) 
	        {
				System.out.print(String.format("%.2f", l)+" ");
	        }      
			if(f1*f2<0) {
				while(r-l>=0.001) {
					double m=(l+r)/2;
					if(f(m)*f(r)<=0) 
		                   l=m; 
		                else 
		                   r=m; 
				}
				System.out.print(String.format("%.2f", r)+" ");
			}
		}
	}
}

(5)P1678 烦恼的高考志愿

发布了26 篇原创文章 · 获赞 18 · 访问量 4622

猜你喜欢

转载自blog.csdn.net/qq_43751506/article/details/105066245