LeetCode每日一题(1840. Maximum Building Height)

You want to build n new buildings in a city. The new buildings will be built in a line and are labeled from 1 to n.

However, there are city restrictions on the heights of the new buildings:

The height of each building must be a non-negative integer.
The height of the first building must be 0.
The height difference between any two adjacent buildings cannot exceed 1.
Additionally, there are city restrictions on the maximum height of specific buildings. These restrictions are given as a 2D integer array restrictions where restrictions[i] = [idi, maxHeighti] indicates that building idi must have a height less than or equal to maxHeighti.

It is guaranteed that each building will appear at most once in restrictions, and building 1 will not be in restrictions.

Return the maximum possible height of the tallest building.

Example 1:

Input: n = 5, restrictions = [[2,1],[4,1]]
Output: 2

Explanation: The green area in the image indicates the maximum allowed height for each building.
We can build the buildings with heights [0,1,2,1,2], and the tallest building has a height of 2.

Example 2:

Input: n = 6, restrictions = []
Output: 5

Explanation: The green area in the image indicates the maximum allowed height for each building.
We can build the buildings with heights [0,1,2,3,4,5], and the tallest building has a height of 5.

Example 3:

Input: n = 10, restrictions = [[5,3],[2,5],[7,4],[10,3]]
Output: 5

Explanation: The green area in the image indicates the maximum allowed height for each building.
We can build the buildings with heights [0,1,2,3,3,4,4,5,4,3], and the tallest building has a height of 5.

Constraints:

  • 2 <= n <= 109
  • 0 <= restrictions.length <= min(n - 1, 105)
  • 2 <= idi <= n
  • idi is unique.
  • 0 <= maxHeighti <= 109

这题自己做出来还是挺有成就感的

整体思路分两个步骤:

  1. 将"虚高"的 restriction 的高度调整到两侧相邻的 restrictions 可以达到的高度, 假设 restrictions = [[10, 10], [11, 1]], 那第一个 restriction 的实际应该是[10, 2], 因为如果我们让 id = 10 的建筑达到 10 的高度, 那一定会违反第二个 restriction, 也就是[11, 1]。我们分别从左右两侧遍历 restrictions, 遇到上升的情况就检查下一个 restriction 的高度是不是超过当前 restriction 的高度的"爬升极限", 如果超过, 则我们要将下一个 restriction 的高度调整到该"极限"

  2. 当完成第一步后,我们拿到的 restrictions 才是"安全"的 restrictions, 我们只要不超过里面任何一个高度限制就可以保证不会存在需要"下降"而降不到所需高度的问题。这样我们就可以安心的遍历所有 restrictions, 所遇到的情况也无非以下三种:

    • 当前高度等于下一个 restriction[1], 这种情况波峰一定出现在(当前 id + restriction[0]) / 2, 最大值为该位置的"爬升极限"
    • 当前高度小于下一个 restriction[1], 如果从当前高度到 restriction[0]的"爬升极限"小于 restriction[1], 那到达 restriction[0]时我们的高度就是该"爬升极限"。如果"爬升极限"大于 restriction[1], 那我们一定能在 restriction[0]之前爬升到与 restriction[1]相同的高度, 假设该 id = m, 那最高高度一定出现在(m + restriction[0]) / 2, 该处的"爬升极限"即为当前段的最大高度
    • 当前高度大于下一个 restriction[1], 那在 restriction[0]之前一定可以存在一个 id = m, height = 当前高度的建筑, 波峰会出现在(当前 id + m) / 2 的位置, 该位置的"爬升极限"就是该段的最大值


impl Solution {
    pub fn max_building(n: i32, mut restrictions: Vec<Vec<i32>>) -> i32 {
        if restrictions.is_empty() {
            return n - 1;
        }
        restrictions.sort_by_key(|l| l[0]);
        for i in (1..restrictions.len()).rev() {
            if restrictions[i - 1][1] > restrictions[i][1] {
                let limit = restrictions[i][1] + restrictions[i][0] - restrictions[i - 1][0];
                if restrictions[i - 1][1] > limit {
                    restrictions[i - 1][1] = limit;
                }
            }
        }
        for i in 0..restrictions.len() - 1 {
            if restrictions[i + 1][1] > restrictions[i][1] {
                let limit = restrictions[i][1] + restrictions[i + 1][0] - restrictions[i][0];
                if restrictions[i + 1][1] > limit {
                    restrictions[i + 1][1] = limit;
                }
            }
        }
        let mut max_height = 0;
        let mut cur_height = 0;
        let mut cur_id = 1;
        for r in restrictions {
            let id = r[0];
            let height = r[1];
            if cur_height == height {
                max_height = max_height.max(cur_height + (id - cur_id) / 2);
                cur_height = height;
                cur_id = id;
                continue;
            }
            if cur_height < height {
                if cur_height + (id - cur_id) <= height {
                    cur_height = cur_height + (id - cur_id);
                    max_height = max_height.max(cur_height);
                    cur_id = id;
                    continue;
                }
                let mid_id = cur_id + (height - cur_height);
                max_height = max_height.max(height + (id - mid_id) / 2);
                cur_height = height;
                cur_id = id;
                continue;
            }
            let mid_id = id - (cur_height - height);
            max_height = max_height.max(cur_height + (mid_id - cur_id) / 2);
            cur_height = height;
            cur_id = id;
        }
        if cur_id < n {
            max_height = max_height.max(cur_height + (n - cur_id))
        }
        max_height
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值