0


快速解决最长递增子序列问题

  LIS(Longest Increasing Subsequence)是比较典型的一个问题,比较容易想到的是**动态规划**解法,时间复杂度是**O(N^2)。**

  先看一下题目,很容易理解:

示例

输入:8

** **[10,9,2,5,3,7,101,18]

输出:4

解释:第一行输入元素个数,第二行输入元素序列。输出最长子序列的长度4.

说明:

  1. 子序列不是子串,子串是连续的,子序列不一定连续。
  2. 满足最长子序列不一定唯一,题目要求的是输出最长子序列的长度,而不是输出最长序列。

动态规划解法

  这题设计使用动态规划算法,我们需要一个**dp数组**(定义的dp数组是可以本质上或者侧面解决实际问题的),假设dp[0...i-1]都已经算出来了,然后反问自己**如何算出的dp[i]**。

  根据题目所求,我们可以这样**定义dp数组:**dp[i]表示以输入数组中**nums[i]这个数结尾**的最长递增子序列的长度。

举两个dp数组的实际意义的例子:

   我们知道dp[i]是表示以输入元素结尾的最长递增子序列的长度后,我们就可以根据这个定义直接求出最终结果(子序列的最长长度)**等价于求dp数组中元素的最大值**。 
  int maxLen = 0;
  for(int i=0;i<dp.size();++i){
  maxLen = max(dp[i],maxLen);
}
  return maxLen;

如何设计算法逻辑去求这个dp数组呢?

这里我们可以采用数学归纳的方法去实现状态转移。

我们在刚刚给的实例中加上个nums[5]:

   如果我们清楚nums[0..4]元素对应的dp[0...4]的大小,我们清楚dp[i]是表示以nums[i]元素结尾的最长增长序列,那么我们**要求nums[5]对应的dp[5],是不是可以直接拿nums[5]和nums[0...4]比较大小,如果nums[5]大,那么dp[5]是不是就在相应的dp[0...4]加1呢。自此会有很多个子序列长度,但是我们要求的是最长子序列的长度,所以我们选择对应加1后最长的子序列就可以了。**
//把j当作0...4,i当作5,就更好理解了
for(int j=0;j<i;++j){
  if(nums[i]>nums[j]&&dp[i]<dp[j]+1)//因为要求的是最长子序列长度,如果对应的dp[j]+1没有dp[i] 
                                      大,那dp[i]保持不变。
    dp[i] = dp[j] + 1;

}
  根据上面的逻辑关系然后以此类推,大致思想就构建完成了

  注:根据dp数组的定义,我们需要给dp数组中元素初始化为1,因为序列长度本身为1。

  根据算nums[5]对应的dp[5]思想可以算其他的元素对应的dp[i]:
for(int i=0;i<nums.size();++i){
  for(int j=0;j<i;++j){
    if(nums[i]>nums[j]&&dp[i]<dp[j]+1)
      dp[i] = dp[j] + 1;
}
}

接下来合并一下就可以写出完整代码了:

#include<bits/stdc++.h>
using namespace std;

int lisLength = 0;//最长递增子序列长度

void lengthOfLis(vector<int> nums,vector<int> dp){
  for(int i=0;i<nums.size();++i){
    for(int j=0;j<i;++j){
      if(nums[i]>nums[j]&&dp[i]<dp[j]+1)
        dp[i] = dp[j] + 1;
}
}
  for(int k=0;k<nums.size();++k){
    lisLength = max(lisLength,dp[k]);
}
}

int main(){
  int n;
  cin>>n;
  vector<int> nums(n);
  vector<int> dp(n,1);   //dp数组中元素赋值为1
  for(int i=0;i<n;++i)
    cin>>nums[i];
  lengthOfLis(nums,dp);
  cout<<lisLength<<endl;
  return 0;
}
  时间复杂度O(N^2).
标签: 算法

本文转载自: https://blog.csdn.net/qq_63691275/article/details/126242092
版权归原作者  ·ᴥ· 所有, 如有侵权,请联系我们删除。

“快速解决最长递增子序列问题”的评论:

还没有评论