问题描述
你是一个冒险家,在一个危机四伏的森林里,你发现了一个隐藏的食物仓库。这个食物仓库由 n 个房间组成,每个房间都有一定数量的食物。你需要找到第一个房间,其中的食物数量大于或等于一个给定的值 x。
这些房间是按食物数量升序排列的。你知道每个房间的食物数量,但由于时间紧迫,你不能一个个房间地去查找。因此,你决定使用二分搜索来快速找到目标房间。
你的任务是编写一个程序,根据每个房间的食物数量和目标值 x,输出第一个食物数量大于或等于 x 的房间的编号。
输入格式
第一行包含一个整数 n,(1≤n≤1e5)(1≤n≤1e5),表示房间的数量。
第二行包含 n 个整数,表示每个房间的食物数量。这些整数是非降序排列的。
第三行包含一个整数 x,(1≤x≤1e9)(1≤x≤1e9),表示目标食物数量。
输出格式
输出一个整数,表示第一个食物数量大于或等于 x 的房间的编号。如果所有房间的食物数量都小于 x,则输出 −1。
样例输入
5 2 5 8 10 15 9
样例输出
4
样例说明
在上述例子中,房间 4 的食物数量为 10,这是第一个大于或等于 9 的值。
测评数据规模
对于 100% 的数据,1≤n≤1e6,并且每个房间的食物数量不超过 1e9。
运行限制
语言 最大运行时间 最大运行内存 C++ 3s 512M C 3s 512M Java 4s 512M Python3 5s 512M PyPy3 5s 512M Go 5s 512M JavaScript 5s 512M
解题思路
题中的 '升序排序'、'二分搜索'等字眼可以让我们想到用二分查找的方法进行求解。
二分查找有 找前任:返回 >= 目标值 的最靠左索引
找后任:返回 <= 目标值 的最靠右索引
找目标值:返回 = 目标值的索引
这几种大致的类型(不全)。
这一题用找前任/后任都可以通过,不过我觉得使用找后任的方法虽然能通过所有的数据,但是万一有若干个相同的x出现,那么找到的索引就是最右侧的x索引,此时就与题中要求(找到第一个>=x的房子编号)相矛盾,所以这个地方我比较推荐使用找前任的方法。
代码
import java.util.Scanner;
public class 寻找食物储量 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
for (int i = 0; i < a.length; i++) {
a[i] = sc.nextInt();
}
int x = sc.nextInt();
int ans = leftmost(a, x);
System.out.println(ans);
}
public static int leftmost(int[] a, int target) {
int i = 0, j = a.length - 1;
while (i <= j) {
int m = (i + j) >>> 1;
//如果目标值target大于当前的数据,那么左边界往右缩
if(a[m] < target) {
i = m + 1;
}
//如果目标值target小于等于当前数据,右边界不断往左缩(为了找到最左侧符合条件的数据)
else {
j = m - 1;
}
}
//由于左侧边界i代表的是索引,若是左边第几个,i还应该 + 1
return (i < a.length)?i + 1:-1;
}
}
ps:学了b站,现学现卖🤭,有不准确的地方还请大家多多指正(●'◡'●)。