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

戳我看原题

解法思路

本题要求对于每个位置i,找出以i为结尾的最长非递减子序列的长度。我们可以利用最长递增子序列(LIS)的贪心+二分优化思路来解决。

  1. 维护数组gg[i]表示长度为i+1的最长非递减子序列的最小末尾元素。
  2. 遍历每个元素:对于每个障碍高度x,使用二分查找在g中找到第一个大于x的位置。
  3. 更新数组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找到插入位置,确保新序列的最小末尾,从而优化后续的扩展可能性。
  • 结果计算:每次插入的位置直接对应当前元素作为结尾的子序列长度,时间复杂度高效。
posted @ 2025-04-03 00:25  Xhita  阅读(37)  评论(0)    收藏  举报