1840. 最高建筑高度
在一座城市里,你需要建 n
栋新的建筑。这些新的建筑会从 1
到 n
编号排成一列。
这座城市对这些新建筑有一些规定:
- 每栋建筑的高度必须是一个非负整数。
- 第一栋建筑的高度必须是
0
。 - 任意两栋相邻建筑的高度差不能超过
1
。
除此以外,某些建筑还有额外的最高高度限制。这些限制会以二维整数数组 restrictions
的形式给出,其中 restrictions[i] = [idi, maxHeighti]
,表示建筑 idi
的高度 不能超过 maxHeighti
。
题目保证每栋建筑在 restrictions
中 至多出现一次 ,同时建筑 1
不会 出现在 restrictions
中。
请你返回 最高 建筑能达到的 最高高度 。
示例 1:
输入:n = 5, restrictions = [[2,1],[4,1]] 输出:2 解释:上图中的绿色区域为每栋建筑被允许的最高高度。 我们可以使建筑高度分别为 [0,1,2,1,2] ,最高建筑的高度为 2 。
示例 2:
输入:n = 6, restrictions = [] 输出:5 解释:上图中的绿色区域为每栋建筑被允许的最高高度。 我们可以使建筑高度分别为 [0,1,2,3,4,5] ,最高建筑的高度为 5 。
示例 3:
输入:n = 10, restrictions = [[5,3],[2,5],[7,4],[10,3]] 输出:5 解释:上图中的绿色区域为每栋建筑被允许的最高高度。 我们可以使建筑高度分别为 [0,1,2,3,3,4,4,5,4,3] ,最高建筑的高度为 5 。
提示:
-
2 <= n <= 1e9
-
0 <= restrictions.length <= min(n - 1, 1e5)
-
2 <= idi <= n
-
idi
是唯一的。 -
0 <= maxHeighti <= 1e9
做题结果
成功,但是想了很久,哈哈速度上不来,开始的时候弄了个循环去硬算左右高度限定后改变的高度,第二遍写了个循环内部再BFS。后面发现仅仅和两侧有关,那左右两边正反循环一遍就行了啊,^_^。
坑
1. 不包含头元素
2. 尾元素可能有可能没有
3. 限高可能有效可能无效,比如第2个限制100,那这个限制就无效
4. 限高可能受到后续影响。比如第一个为0,第三个限高2,第四个限高0,由于后续第四个元素影响,第三个只能最高到达 1,到不了2
方法:贪心
- 按照位置排序
- 不含第一栋建筑补第一栋
- 如果含有最后一栋建筑不用补,否则补一个最后一栋
- 对于编号为 i 的建筑,最高为 i-1,先粗略的写个限定
- 由于前后限定的值都对当前元素产生影响,不一定能达到限定值,所以按照左右都改一遍限定值,
curr=min(pre[1]+(curr[0]-pre[0]),curr[1])
,保证了从前面可以到达后面的高度,反过来保证了从后面可以到达前面的高度(注意:特别小心最后一个元素的处理,从前往后推导是包含最后一个元素的,从后往前不包含) - 推导两个限定高度之间的最大高度:
(curr[0]-pre[0]-Math.abs(curr[1]-pre[1]))/2+max(pre[1],curr[1]);
- 首先两者的较大值是 max(pre[1],curr[1])
- 然后需要把较小的一个补到最大值,需要 abs(curr[1]-pre[1]) 的距离
- 两者水平距离是 curr[0]-pre[0],需要刨除掉补到最大值的距离,就变成
curr[0]-pre[0]-Math.abs(curr[1]-pre[1])
- 最后他们的距离除以2,是中间可以突出来的高度,比如 2,4 两个位置高度都是 3,4-2是2,除以2是1,所以中间可以突出1个单位的高度,2+1 得到 3
class Solution {
public int maxBuilding(int n, int[][] restrictions) {
List<int[]> heights = new ArrayList<>();
heights.add(new int[]{1,0});
int m = restrictions.length;
Arrays.sort(restrictions,(a,b)->a[0]-b[0]);
for(int []restrict:restrictions){
restrict[1] = Math.min(restrict[1],restrict[0]-1);
}
heights.addAll(Arrays.asList(restrictions));
//调好限定高度,有些高度可能是坑
if(heights.get(heights.size()-1)[0]!=n) heights.add(new int[]{n,n-1});
for(int i = 1; i < heights.size(); i++){
int[] pre = heights.get(i-1);
int[] curr = heights.get(i);
int m1 = pre[1]+(curr[0]-pre[0]);
curr[1] = Math.min(m1,curr[1]);
}
for(int i = heights.size()-2; i >0 ; i--){
int[] next = heights.get(i+1);
int[] curr = heights.get(i);
int m1 = next[1]+(next[0]-curr[0]);
curr[1] = Math.min(m1,curr[1]);
}
//(end-start-abs(v[end]-v[start]))/2+max(v[end],v[start])
int ans = 0;
for(int i = 1; i < heights.size(); i++){
int[] pre = heights.get(i-1);
int[] curr = heights.get(i);
int max = (curr[0]-pre[0]-Math.abs(curr[1]-pre[1]))/2+Math.max(pre[1],curr[1]);
ans = Math.max(max,ans);
}
return ans;
}
}
时间复杂度:O(nlogn)
空间复杂度:O(n),可以优化到O(1),直接在原数组基础上修改,判断头尾