LeetCode 题解工作台

找出到每个位置为止最长的有效障碍赛跑路线

你打算构建一些障碍赛跑路线。给你一个 下标从 0 开始 的整数数组 obstacles ,数组长度为 n ,其中 obstacles[i] 表示第 i 个障碍的高度。 对于每个介于 0 和 n - 1 之间(包含 0 和 n - 1 )的下标 i ,在满足下述条件的前提下,请你找出 obstacle…

category

3

题型

code_blocks

5

代码语言

hub

3

相关题

当前训练重点

困难 · 二分·搜索·答案·空间

bolt

答案摘要

我们可以用树状数组维护一个最长递增子序列的长度数组。 然后对于每个障碍,我们在树状数组中查询小于等于当前障碍的最长递增子序列的长度,假设为 ,那么当前障碍的最长递增子序列的长度为 ,我们将 添加到答案数组中,并将 更新到树状数组。

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 二分·搜索·答案·空间 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

你打算构建一些障碍赛跑路线。给你一个 下标从 0 开始 的整数数组 obstacles ,数组长度为 n ,其中 obstacles[i] 表示第 i 个障碍的高度。

对于每个介于 0n - 1 之间(包含 0n - 1)的下标  i ,在满足下述条件的前提下,请你找出 obstacles 能构成的最长障碍路线的长度:

  • 你可以选择下标介于 0i 之间(包含 0i)的任意个障碍。
  • 在这条路线中,必须包含第 i 个障碍。
  • 你必须按障碍在 obstacles 中的 出现顺序 布置这些障碍。
  • 除第一个障碍外,路线中每个障碍的高度都必须和前一个障碍 相同 或者 更高

返回长度为 n 的答案数组 ans ,其中 ans[i] 是上面所述的下标 i 对应的最长障碍赛跑路线的长度。

 

示例 1:

输入:obstacles = [1,2,3,2]
输出:[1,2,3,3]
解释:每个位置的最长有效障碍路线是:
- i = 0: [1], [1] 长度为 1
- i = 1: [1,2], [1,2] 长度为 2
- i = 2: [1,2,3], [1,2,3] 长度为 3
- i = 3: [1,2,3,2], [1,2,2] 长度为 3

示例 2:

输入:obstacles = [2,2,1]
输出:[1,2,1]
解释:每个位置的最长有效障碍路线是:
- i = 0: [2], [2] 长度为 1
- i = 1: [2,2], [2,2] 长度为 2
- i = 2: [2,2,1], [1] 长度为 1

示例 3:

输入:obstacles = [3,1,5,6,4,2]
输出:[1,1,2,3,2,2]
解释:每个位置的最长有效障碍路线是:
- i = 0: [3], [3] 长度为 1
- i = 1: [3,1], [1] 长度为 1
- i = 2: [3,1,5], [3,5] 长度为 2, [1,5] 也是有效的障碍赛跑路线
- i = 3: [3,1,5,6], [3,5,6] 长度为 3, [1,5,6] 也是有效的障碍赛跑路线
- i = 4: [3,1,5,6,4], [3,4] 长度为 2, [1,4] 也是有效的障碍赛跑路线
- i = 5: [3,1,5,6,4,2], [1,2] 长度为 2

 

提示:

  • n == obstacles.length
  • 1 <= n <= 105
  • 1 <= obstacles[i] <= 107
lightbulb

解题思路

方法一:树状数组

我们可以用树状数组维护一个最长递增子序列的长度数组。

然后对于每个障碍,我们在树状数组中查询小于等于当前障碍的最长递增子序列的长度,假设为 ll,那么当前障碍的最长递增子序列的长度为 l+1l+1,我们将 l+1l+1 添加到答案数组中,并将 l+1l+1 更新到树状数组。

时间复杂度 O(n×logn)O(n \times \log n),空间复杂度 O(n)O(n)。其中 nn 为障碍的数量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class BinaryIndexedTree:
    __slots__ = ["n", "c"]

    def __init__(self, n: int):
        self.n = n
        self.c = [0] * (n + 1)

    def update(self, x: int, v: int):
        while x <= self.n:
            self.c[x] = max(self.c[x], v)
            x += x & -x

    def query(self, x: int) -> int:
        s = 0
        while x:
            s = max(s, self.c[x])
            x -= x & -x
        return s


class Solution:
    def longestObstacleCourseAtEachPosition(self, obstacles: List[int]) -> List[int]:
        nums = sorted(set(obstacles))
        n = len(nums)
        tree = BinaryIndexedTree(n)
        ans = []
        for x in obstacles:
            i = bisect_left(nums, x) + 1
            ans.append(tree.query(i) + 1)
            tree.update(i, ans[-1])
        return ans
speed

复杂度分析

指标
时间complexity is O(n log n) if using binary search for each obstacle to find its place in the tracking array. Space complexity is O(n) to store the tracking array and the result ans.
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Look for a binary search solution to handle large input sizes efficiently.

  • question_mark

    Consider how to maintain minimum heights per course length to extend sequences correctly.

  • question_mark

    Watch for edge cases where obstacles decrease or repeat, impacting sequence length.

warning

常见陷阱

外企场景
  • error

    Failing to maintain the minimum height for each course length can produce shorter sequences than possible.

  • error

    Using linear scan instead of binary search leads to TLE on large inputs.

  • error

    Incorrectly updating the tracking array can overwrite valid sequences and reduce the final answer.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Find the longest strictly increasing obstacle course at each position.

  • arrow_right_alt

    Compute the total number of distinct valid obstacle courses ending at each index.

  • arrow_right_alt

    Determine the maximum obstacle course length if only adjacent elements can be used.

help

常见问题

外企场景

找出到每个位置为止最长的有效障碍赛跑路线题解:二分·搜索·答案·空间 | LeetCode #1964 困难