问题描述
牛妹需要用 n 根桥柱搭建一座桥,第一根桥柱和最后一根桥柱的高度已经确定,分别为 a 和 b。 为了保证桥梁的稳固性,相邻桥柱的高度差不能超过 1。牛妹想知道,在保证稳固性的前提下,桥梁中最高的桥柱能有多高。你需要帮助牛妹计算桥梁最高的桥柱的高度。
思路
根据题目的描述,我们希望尽可能的把桥柱往高建,也就是从一端尽可能把桥建高,之后到达某一个高度之后,我们能够在剩余桥柱数量内,回到另一端的高度,也就是所有桥柱的高度可以形成一个类似于二次函数的形状,我们要做的就是找到这个二次函数的最大值
这样问题就转变为,给定两端点值,如何找到最大值
首先可以枚举中点 mid。
我们可以想象从左端点加高到 mid,再从 mid 降低到右端点。
如果这个过程
-
最后降低到右侧以下,说明 mid 太小,降低太多
-
降低到右侧以上,说明 mid 太大,降低太少
在这个过程中,我们发现答案是由单调性的,也就是如果一个 mid 太小,那么更小的 mid 一定也不满足答案。
所以我们可以二分来找这个合适 mid
-
小于等于右侧:mid 过小,l = mid + 1
-
大于右侧:mid 过大,r = mid + 1
最后答案 l 是不满足要求的开始
所以最大高度就是 a + l - 1
由于如果到达不了右侧,需要返回 -1
所以返回时判断,如果当前找到的最大高度,小于两侧的最大值,那么返回 -1,否则返回找到的答案
解题方法
初始化左右端点,维护 mid 即左右端点的中间点
根据中间点计算最大高度 h
判断当前最大高度下降到右侧的高度与右侧当前高度
-
小于等于右侧 l = mid + 1:说明中间点在 [mid + 1, r) 范围上
-
大于右侧 r = mid - 1:说明中间点在 (l, mid - 1] 范围上
最后根据中间点计算最高高度
最后判断特殊情况,根据正确格式返回答案
复杂度
时间复杂度:
O(\log N)
对于给定的桥墩,二分查找最高的桥墩位置 O(\log N)
空间复杂度:
O(1)
仅使用个别变量 O(1)
代码
public class Main {
public static int solution(int n, int a, int b) {
int l = 0, r = n - 1;
while (l <= r) {
int mid = l + ((r - l) >> 1);
int h = a + mid;
if (h - n + 1 + mid <= b) l = mid + 1;
else r = mid - 1;
}
int ans = l - 1 + a;
return ans < Math.max(a, b) ? -1 : ans;
}
public static void main(String[] args) {
System.out.println(solution(2, 1, 1) == 1);
System.out.println(solution(3, 1, 1) == 2);
System.out.println(solution(5, 3, 2) == 4);
System.out.println(solution(5, 1, 100) == -1);
System.out.println(solution(4, 1, 4) == 4);
}
}