题目解析
给定一个整数数组 nums,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

测试用例
输入:nums = [10,9,2,5,3,7,101,18] 输出:4 解释:最长递增子序列是 [2,3,7,101],因此长度为 4。

算法原理
这道题最直观的解法是动态规划,时间复杂度为 O(N^2)。但在实际工程中,我们往往追求更优的性能。通过观察可以发现,对于相同长度的递增子序列,末尾元素越小,后续扩展的可能性就越大。这就是贪心策略的核心:维护一个有序数组,记录不同长度子序列的最小末尾值。

贪心思路
假设我们有一个数组 tails,其中 tails[i] 表示长度为 i+1 的递增子序列的最小末尾元素。这个数组本身一定是有序的。当我们遍历原数组时,如果当前数字比 tails 中所有元素都大,就可以直接追加到末尾,增加子序列长度;否则,我们需要在 tails 中找到第一个大于等于当前数字的位置并替换它。这样做的目的是让该长度的子序列末尾变得更小,从而为后续元素留出更多空间。

具体实现
为了快速找到插入位置,我们可以使用二分查找。这样可以将查找过程的时间复杂度从 O(N) 降低到 O(logN),整体算法复杂度优化为 O(N logN)。

实战代码
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
(nums.()) ;
vector<> dp;
dp.(nums[]);
( i = ; i < nums.(); i++) {
(nums[i] > dp.()) {
dp.(nums[i]);
} {
left = , right = dp.();
(left < right) {
mid = (left + right) >> ;
(nums[i] > dp[mid]) {
left = mid + ;
} {
right = mid;
}
}
dp[left] = nums[i];
}
}
dp.();
}
};



