【JAVA】PAT 1060 爱丁顿数 二分查找JAVA版

【JAVA】PAT 1060 爱丁顿数 二分查找JAVA版


题目链接
英国天文学家爱丁顿很喜欢骑车。据说他为了炫耀自己的骑车功力,还定义了一个“爱丁顿数” E ,即满足有 E 天骑车超过 E 英里的最大整数 E。据说爱丁顿自己的 E 等于87。

现给定某人 N 天的骑车距离,请你算出对应的爱丁顿数 E(≤N)。

输入格式:
输入第一行给出一个正整数 N (≤10​5​​ ),即连续骑车的天数;第二行给出 N 个非负整数,代表每天的骑车距离。

输出格式:
在一行中给出 N 天的爱丁顿数。

输入样例:

10
6 7 6 9 3 10 8 2 7 8

输出样例:

6

这题看明白题意后,其实思路很简单,把输入按非递增顺序排列
JAVA让数组按非递增方式排序的方法:

Comparator<Integer> t = new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				return o2 - o1;
			}
		};
Arrays.sort(a, t);

要注意Arrays.sort的参数是sort(T[] a, Comparator<? super T> c),不能用int[]来排序,要用Integer[]。

然后一个个看第i个元素的值是不是大于i+1(i从0开始),E=i+1,当小于或等于的时候,退出循环。不过直接写的话第三个测试点会超时

测试点3超时代码:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;
import java.util.Comparator;

public class Main {
	public static void main(String[] args) throws Exception {
		BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
		PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
		StreamTokenizer in = new StreamTokenizer(bf);
		in.nextToken();
		int N = (int) in.nval;
		Integer[] a = new Integer[N];
		for (int i = 0; i < N; i++) {
			in.nextToken();
			a[i] = (int) in.nval;
		}
		Comparator<Integer> t = new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				return o2 - o1;
			}
		};
		Arrays.sort(a, t);
		int E = 0;
		for (int i = 0; i < a.length; i++) {
			if (a[i] > (i + 1)) {
				E = i+1;
			} else {
				break;
			}
		}
		out.print(E);
		out.flush();
	}

}

于是我想是不是一个个遍历太慢了,需要二分法来。边界一直没处理好,老是报错或者Wrong Answer。最后终于AC了

这道题用二分查找的逻辑是要比较a[mid]是不是大于mid+1,同时还要比较mid两边的元素。

  • 如果a[mid]>mid+1,还要判断是否a[mid+1]<=mid+2,是的话E=mid+1,否则继续查找。
  • 如果a[mid]<=mid+1,还要判断是否a[mid - 1] > mid,是的话E=mid,否则继续查找。

二分查找代码:

	static int findE(Integer[] a) {
		int E = 0;
		int l = 0, r = a.length - 1;
		while (l <= r) {
			int mid = (l + r) / 2;
			if (a[mid] <= mid + 1) {
				if (a[mid - 1] > mid) {
					E = mid;
					break;
				}
				r = mid - 1;
			} else {
				if (a[mid + 1] <= mid + 2) {
					E = mid + 1;
					break;
				}
				l = mid + 1;
			}
		}
		return E;
	}

由于要比较a[mid]两边的元素,所以还要做一些处理,以防数组越界

  • N=1的时候直接判断a[0]是不是大于1
  • N=2的时候遍历数组
  • N>2的时候再二分查找,同时如果a[0],也就是最大值小于等于1的话直接E=0,不然也会越界
	if (N == 1) {
		if (a[0] > 1)
			E = 1;
	} else if (N == 2) {
		for (int i = 0; i < a.length; i++) {
			if (a[i] <= i + 1) {
				E = i;
				break;
			}
			E = i + 1;
		}
	} else {
		if (a[0] <= 1) {
			E = 0;
		} else {
			E = findE(a);//二分查找
		}
	}

AC代码(二分查找):

import java.util.Arrays;
import java.util.Comparator;
import java.io.BufferedReader;
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 Exception {
		BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
		PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
		StreamTokenizer in = new StreamTokenizer(bf);
		in.nextToken();
		int N = (int) in.nval;
		int E = 0;
		int min = Integer.MAX_VALUE;
		Integer[] a = new Integer[N];
		for (int i = 0; i < N; i++) {
			in.nextToken();
			int tem = (int) in.nval;
			a[i] = tem;
			min = min < tem ? min : tem;
		}
		if (min > N) {
			E = N;
		} else {
			Arrays.sort(a, new Comparator<Integer>() {
				@Override
				public int compare(Integer o1, Integer o2) {
					return o2 - o1;
				}
			});

			if (N == 1) {
				if (a[0] > 1)
					E = 1;
			} else if (N == 2) {
				for (int i = 0; i < a.length; i++) {
					if (a[i] <= i + 1) {
						E = i;
						break;
					}
					E = i + 1;
				}
			} else {
				if (a[0] <= 1) {
					E = 0;
				} else {
					E = findE(a);
				}
			}
		}
		out.print(E);
		out.flush();
	}

	static int findE(Integer[] a) {
		int E = 0;
		int l = 0, r = a.length - 1;
		while (l <= r) {
			int mid = (l + r) / 2;
			if (a[mid] <= mid + 1) {
				if (a[mid - 1] > mid) {
					E = mid;
					break;
				}
				r = mid - 1;
			} else {
				if (a[mid + 1] <= mid + 2) {
					E = mid + 1;
					break;
				}
				l = mid + 1;
			}
		}
		return E;
	}
}

后来去网上看了下别人写的代码和测试点分析,测试点3是所有元素都大于N,这个时候直接输出N就好了,不用一个个遍历。于是我在之前不是二分查找的代码试了一下

判断所有元素是否大于N,一开始我是写在排完序后面

	Arrays.sort(a, t);
	if (a[a.length-1] > N) {
		E = N;
	} else {
		......//遍历数组
	}

但还是超时了,想了想,在输入的时候就把最小的值记录下来,然后试了试

	for (int i = 0; i < N; i++) {
		in.nextToken();
		a[i] = (int) in.nval;
		min = min < a[i] ? min : a[i];
	}
	if (min > N) {
		E = N;
	} else {
		......//排序,遍历数组
	}
	out.print(E);
	out.flush();

然后通过了…
还是我太菜了…

遍历数组完整AC代码:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;
import java.util.Comparator;

public class Main {
	public static void main(String[] args) throws Exception {
		BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
		PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
		StreamTokenizer in = new StreamTokenizer(bf);
		in.nextToken();
		int N = (int) in.nval;
		int E = 0;
		int min = Integer.MAX_VALUE;
		Integer[] a = new Integer[N];
		for (int i = 0; i < N; i++) {
			in.nextToken();
			a[i] = (int) in.nval;
			min = min < a[i] ? min : a[i];
		}
		if (min > N) {
			E = N;
		} else {
			Comparator<Integer> t = new Comparator<Integer>() {
				@Override
				public int compare(Integer o1, Integer o2) {
					return o2 - o1;
				}
			};
			Arrays.sort(a, t);
			for (int i = 0; i < a.length; i++) {
				if (a[i] > (i + 1)) {
					E = i + 1;
				} else {
					break;
				}
			}
		}
		out.print(E);
		out.flush();
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值