1964. 找出到每个位置为止最长的有效障碍赛跑路线
解法思路
本题要求对于每个位置i,找出以i为结尾的最长非递减子序列的长度。我们可以利用最长递增子序列(LIS)的贪心+二分优化思路来解决。
- 维护数组
g:g[i]表示长度为i+1的最长非递减子序列的最小末尾元素。 - 遍历每个元素:对于每个障碍高度
x,使用二分查找在g中找到第一个大于x的位置。 - 更新数组
g和答案:- 若位置在末尾,说明
x可扩展最长子序列,将其加入g,当前长度为g的长度。 - 否则,替换该位置的元素为
x,当前长度为该位置索引+1。
- 若位置在末尾,说明
复杂度
- 时间复杂度:O(n log n),每个元素二分查找的时间为O(log n)。
- 空间复杂度:O(n),用于存储数组
g和结果。
代码
#include <vector>
#include <algorithm> // For ranges::upper_bound
class Solution {
public:
std::vector<int> longestObstacleCourseAtEachPosition(std::vector<int>& obstacles) {
std::vector<int> g, result;
for (int x : obstacles) {
// 查找第一个大于x的元素的位置
auto it = std::ranges::upper_bound(g, x);
if (it == g.end()) {
g.push_back(x);
result.push_back(g.size());
} else {
*it = x;
result.push_back(it - g.begin() + 1);
}
}
return result;
}
};
解释
- 数组
g的维护:始终保持g的严格递增性质,但允许子序列非递减。通过替换第一个大于当前元素的位置,保证后续元素更容易形成更长的序列。 - 二分查找:使用
upper_bound找到插入位置,确保新序列的最小末尾,从而优化后续的扩展可能性。 - 结果计算:每次插入的位置直接对应当前元素作为结尾的子序列长度,时间复杂度高效。

浙公网安备 33010602011771号