编程实现最长上升子序列(LIS)的方法有多种,以下提供两种常见的方法:
方法一:动态规划
定义状态
设 `dp[i]` 表示以 `a[i]` 为结尾的最长上升子序列的长度。
状态转移方程
对于每个元素 `a[i]`,遍历其之前的所有元素 `a[j]`(其中 `j < i`),如果 `a[j] < a[i]`,则 `dp[i] = max(dp[i], dp[j] + 1)`。
初始化
`dp[i] = 1`,因为每个元素本身可以构成长度为1的上升子序列。
计算顺序
从左到右依次计算每个 `dp[i]`。
结果
最终 `dp` 数组中的最大值即为最长上升子序列的长度。
示例代码:
```cpp
include include include using namespace std; int lis_dp(vector int n = nums.size(); vector int max_len = 1; for (int i = 1; i < n; ++i) { for (int j = 0; j < i; ++j) { if (nums[j] < nums[i]) { dp[i] = max(dp[i], dp[j] + 1); } } max_len = max(max_len, dp[i]); } return max_len; } int main() { vector cout << "Length of LIS is " << lis_dp(nums) << endl; return 0; } ``` 方法二:二分查找 设 `dp[i]` 表示以 `a[i]` 为结尾的最长上升子序列的长度。 设 `len` 表示当前找到的最长上升子序列的长度。 使用二分查找找到 `dp[i]` 的最大值。 维护一个数组 `d`,其中 `d[len]` 表示长度为 `len` 的上升子序列的最小末尾元素。 `dp[i] = 1`,因为每个元素本身可以构成长度为1的上升子序列。 `len = 1`,`d = a`。 从左到右依次计算每个 `dp[i]`,并更新 `d` 数组。 最终 `len` 即为最长上升子序列的长度。 示例代码: ```cpp include include include using namespace std; int lis_binary_search(vector int n = nums.size(); vector int len = 1; vector d = nums; for (int i = 1; i < n; ++i) { if (nums[i] > d[len]) { d[++len] = nums[i]; } else { auto it = lower_bound(d.begin(), d.begin() + len + 1, nums[i]); *it = nums[i]; } } return len; } int main() { vector cout << "Length of LIS is " << lis_binary_search(nums) << endl; return 0; } ``` 编程语言选择 Java:适用于企业级应用程序,具有强大的跨平台性和可扩展性。 C:拥有强大的.NET框架支持,适合快速开发可靠的医院定义状态
状态转移方程
初始化
计算顺序
结果