最长递增子序列
一、题目
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
例子:
1 2 3
| 输入:nums = [10,9,2,5,3,7,101,18] 输出:4 解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
|
Leetcode:https://leetcode.cn/problems/longest-increasing-subsequence/
二、思路
动态规划思路,定义 dp 数组,数组长度为 nums 的长度。当数组 nums 只有第一个元素时,那么最长递增子序列为1;当有 N 个元素的时候,dp[N]
的位置的值,应该如何求呢?我们遍历 0 到 N-1 位置,如果 nums[N] > nums[i]
,那么此时就有 dp[N] = max(dp[N], dp[i]+1)
。需要注意,此时 dp 数组的最后一个元素不一定是最长递增子序列的长度。因为并没有依次给 dp 数组赋值,而是有条件性的赋值,条件即为:nums[N] > nums[i]
。所以我们可以用一个变量来记录最值。
延伸一下,如果要这个最长递增子序列呢?而不是求长度。
也比较简单,dp 数组已经记录了以某个位置为结尾的数组的最长递增子序列。那么我们先取到最大的那个位置,依次往前找,比如最后一个位置为 max_pos,依次往前找 i,那么有 dp[i] == dp[max_pos]-1
的时候,既可以取 nums 的位置的元素。
三、代码
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| #include <vector> #include <algorithm> #include <iostream>
class Solution { public: int lengthOfLIS(std::vector<int>& nums) { if (nums.empty()) return 0; std::vector<int> dp(nums.size(), 0); int max_val = 0; for (size_t i = 0; i < nums.size(); ++i) { dp[i] = 1; for (size_t j = 0; j < i; ++j) { if (nums[j] < nums[i]) { dp[i] = std::max(dp[i], dp[j]+1); } } if (dp[i] > max_val) { max_val = dp[i]; } } return max_val; } };
class Solution_02 { public: std::vector<int> lengthOfLIS(std::vector<int>& nums) { if (nums.empty()) return std::vector<int>(); std::vector<int> dp(nums.size(), 0); int max_pos = 0, max_val = 0; for (size_t i = 0; i < nums.size(); ++i) { dp[i] = 1; for (size_t j = 0; j < i; ++j) { if (nums[j] < nums[i]) { dp[i] = std::max(dp[i], dp[j]+1); } } if (dp[i] > max_val) { max_val = dp[i]; max_pos = i; } } std::vector<int> res; res.emplace_back(nums[max_pos]); int prev = max_pos; for (int i = max_pos-1; i >= 0; --i) { if (dp[i] == dp[prev]-1) { res.emplace_back(nums[i]); prev = i; } } std::reverse(res.begin(), res.end()); return res; } };
void print_vec(const std::vector<int>& vec) { for (const auto& x : vec) { std::cout << x << " "; } std::cout << std::endl; }
int main() { Solution_02 s; std::vector<int> vec{2, 1, 5, 3, 6, 4, 8, 9, 7}; auto res = s.lengthOfLIS(vec); print_vec(res); return 0; }
|
不过这个方法的时间复杂度是 O(N2),空间复杂度是 O(n)。这里还有可优化的空间。待优化