每日一题之最长上升子序列

题目:

有一个长为n的数列a0,a1,...,an-1。请求出这个序列中最长的上升子序列的长度。上升子序列指的是对于仍以的 i<j 都满足ai<aj 的子序列。1 <= n <= 1000 ,0<= ai <= 1000000。

输入样例:
5 4 2 3 1 5
输出样例:

3 (a1,a2,a4构成子序列2,3,5最长)


思路1:

这个问题是被称为最长子序列。可以通过DP的方法来求解。

定义dp[i]为以ai为末尾的最长上升子序列的长度。以ai为结尾的上升子序列有两种情况

1,只包含,ai

2,包含一个以aj为结尾的上升子序列,再追加上 ai,其中 aj<ai。

所以可以写出地推关系:

dp[i]=max{1,dp[j]+1 | j<i 且 aj<ai}

通过该方法的时间复杂度为 O(n^2).

int n;
int a[MAXN];
int dp[MAXN];

void solve()
{
    int ans=0;
    for(int i=0;i<n;i++)
    {
        dp[i]=1;
        for(int j=0;j<i;j++)
        {
            if (a[j]<a[i])
            {
                dp[i]=max(dp[i],dp[j]+1);                
            }
            ans=max(anx,dp[i]);
        }
    }
    cout<<ans<<endl;
}

思路2:

通过二分搜索的方法实现。

首先,思考这样一个问题:对于数列p={1,2,4,3,5,6,7},在中间某一步计算结束后,我们得到了两个长度为3的上升子序列,分别为,p1={1,2,3},p2={3,5,6}。请问p1和p2哪个更加有“潜力”,显然p1的潜力更大一些,因为p1中最大的数字比p2中的数字小。

所以可以通过栈的思想来做,在依次遍历数列的过程中,当遍历到数字ai的时候,当ai>top的时候,ai进栈,成为新的top。当ai<top的时候,二分查找栈中元素,找出第1个比ai大的数字,比讲它替换,得到新的栈。该栈中元素的个数就是最长上升序列的个数。

数列:1,5,7,2, 3,6

栈中元素: 1,5,7。2进栈替换5,变成,1,2,7。同理3替换7,得到:1,2,3。最后6进栈,得到,1,2,3,6。最长子序列为4

该方法的时间复杂度是,nlogn。缺点是,不能得到正确的序列。

void solve()
{
    int i, j, n, top, temp;
    int arr[1010];//用数组代替栈
    cin >> n;
    top = 0;
    arr[0] = -1;
    for (i = 0; i < n; i++)
    {
        cin >> temp;
        if (temp > arr[top])
        {
            arr[++top] = temp;
        }
        else//二分查找
        {
            int low = 1, high = top;
            int mid;
            while(low <= high)
            {
                mid = (low + high) / 2;
                if (temp > arr[mid])
                {
                    low = mid + 1;
                }
                else
                {
                    high = mid - 1;
                }
            }
            arr[low] = temp;
        }
    }
    cout << top << endl;

}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值