[最值问题]最长递增子序列

核心思想:
    dp[i] = max{dp[j]+1} 0<=j<i and a[j]<a[i]
维护单调队列d,其中队列的值为a数组的值,队列d中的每一个元素分别对应一个以该元素结尾的一个子序列,注意队列并不能保存改子序列的所有值的信息。
if a[i]>d[len]
    d[len++]=a[i]
else
   d[j+1]=a[i] and d[j]是第一个比a[i]小的数,因为我们应该尽量使得子序列末尾的元素小,长度才有可能长
构建单调队列的时候有以下几种情况:
1.只有一个元素
  d[0]=a[i]
2.有两个元素a[low],a[high]
  if a[low]<a[i]
     d[high]=a[i]
  else if a[low]>a[i]
     d[low]=a[i]
  else
     不用交换,这里存在a[i]与d[low]与d[high]相等的情况

题目:点击打开链接

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 10005
using namespace std;
int n,len=0;
char a[N],d[N];
void input()
{
    len=0;
    cin>>a;
    n=strlen(a);
}
void search(char key)
{
    int low,high,mid;
    low=0,high=len-1;
    while(low<high-1)
    {
        mid=(low+high)>>1;
        if(key==d[mid])
        {
            return ;
        }
        else if(key>d[mid])
            low=mid;
        else
        {
            high=mid;
        }
    }
    if(d[low]>key)
        d[low]=key;
    else if (d[low]<key)
        d[high]=key;
}
void getLIS()
{
    for(int i=0; i<n; i++)
    {
        if(len==0||a[i]>d[len-1])
            d[len++]=a[i];
        else
        {
            search(a[i]);
        }
    }
    cout<<len<<endl;
}
int main()
{
    int m;
    cin>>m;
    while(m--)
    {
        input();
        getLIS();
    }
    return 0;
}

1.改进:计算最长不递减子序列。

那么不能使用单调队列来优化,因为单调队列中存在相等的元素,那么新元素加入队列时,两种情况如下:

1.如果新元素比单调队列最后的元素大的话,加入队列后面。

2.如果新元素比单调队列最后的元素小的话:

2.1 如果队列中存在与该元素相等的元素,则需要加入队列中与它相等的元素后面。但是队列后面的元素的位置则发生了变化,所以破坏了队列所代表的含义,即每个元素都对应一个以该元素结尾,长度为改元素位置的子序列。

2.2 如果队列中不存在与该元素相等的元素,那么直接找到第一个比该元素大的元素,替换它就好了。

所以,这里只能使用O(n^2)的算法来计算,即dp[i] = max{dp[j]+1}  a[j] <= a[i] and 0<=j<=i


动态规划是一种解决最值问题的方法,其中最长递增子序列问题是其中的一个典型应用。在这个问题中,我们需要找到一个给定序列中最长的递增子序列。 动态规划解决最长递增子序列问题的一般步骤如下: 1. 创建一个长度与原始序列相同的dp数组,用来存储以当前元素为结尾的最长递增子序列的长度。 2. 初始化dp数组的每个元素为1,表示以该元素为结尾的最长递增子序列的长度至少为1。 3. 从序列的第二个元素开始,遍历整个序列。 4. 对于每个元素,再次遍历该元素之前的所有元素。 5. 如果当前元素大于前面的某个元素,并且以该前面的元素为结尾的最长递增子序列长度加1大于当前元素所在位置的dp数组的值,则更新当前元素的dp数组的值为该长度。 6. 最后,遍历整个dp数组,找到最大值,即为最长递增子序列的长度。 根据上述步骤,我们可以使用普通的动态规划算法来解决最长递增子序列问题,其时间复杂度为O(N^2)。引用介绍了动态规划方法在解决最长递增子序列问题时的应用。引用指出了在解决该问题时,需要按照第一维参数进行升序排序,然后按照第二维参数降序排序。而引用中的代码展示了如何利用dp数组来求得最长递增子序列的长度。 因此,根据上述引用内容,可以总结出通过动态规划来解决最长递增子序列问题的一般方法和相关注意事项。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [动态规划算法 | 最长递增子序列](https://blog.csdn.net/qq_38844835/article/details/127464625)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值