【LIS】O(nlogn)二分法搜索+路径输出

 看了很多博客,都只是介绍了如何去找最大的长度,而没有介绍如果去存取这个路径,问了实验室的学长,学长说他也不会,开始的时候,我以为模拟的栈中的元素存的就是最长子序列,其实不然,在搜索替换的过程中,为了保证尽量的增加后续的潜力,就尽量的把前面的序列在原有的长度上变下,所以我就会去找到第一个比当前数大的元素,然后替换掉,但是在这里替换就会发现一个问题是,当前元素可能会排到之前元素的前面,所以导致顺序颠倒,所以我们这里需要记住每一个元素曾经出现在最长子序列中的位置,然后我们反向查找,第一个遇到的就是真正LIS中的元素。

    sequence : -7 10  9  2  3  8  8  1
    temp LIS :
    position :
     
    sequence :(-7)10  9  2  3  8  8  1
    temp LIS : -7
    position :  1       // -7 在 LIS 的第一個位置
     
    sequence : -7(10) 9  2  3  8  8  1
    temp LIS : -7 10
    position :  1  2    // 10 在 LIS 的第二個位置,以此類推。
     
    sequence : -7 10 (9) 2  3  8  8  1
    temp LIS : -7  9
    position :  1  2  2
    /* 9 成為 LIS 的潛力比 10 大, 所以以 9 代替 10 */
     
    sequence : -7 10  9 (2) 3  8  8  1
    temp LIS : -7  2
    position :  1  2  2  2
    /* 2 成為 LIS 的潛力比 9 大, 所以以 2 代替 9 */
     
    sequence : -7 10  9  2 (3) 8  8  1
    temp LIS : -7  2  3
    position :  1  2  2  2  3
     
    sequence : -7 10  9  2  3 (8) 8  1
    temp LIS : -7  2  3  8
    position :  1  2  2  2  3  4
     
    sequence : -7 10  9  2  3  8 (8) 1
    temp LIS : -7  2  3  8
    position :  1  2  2  2  3  4  4
    /* 8 成為 LIS 的潛力比 8 大, 所以以 8 代替 8 */
     
    sequence : -7 10  9  2  3  8  8 (1)
    temp LIS : -7  1  3  8
    position :  1  2  2  2  3  4  4  2
    /* 1 成為 LIS 的潛力比 2 大, 所以以 1 代替 2 */

因為 LIS 長度為 4 ,所以就先找位置為 4 的
    sequence : -7 10  9  2  3  8 (8) 1
    position :  1  2  2  2  3  4 (4) 2
    LIS      :  -  -  -  8
    /* search 4th, 8 is fourth LIS element */
     
    sequence : -7 10  9  2 (3) 8  8  1
    position :  1  2  2  2 (3) 4  4  2
    LIS      :  -  -  3  8
    /* search 3rd, 3 is third LIS element */
     
    sequence : -7 10  9 (2) 3  8  8  1
    position :  1  2  2 (2) 3  4  4  2
    LIS      :  -  2  3  8
    /* search 2nd, 2 is second LIS element */
     
    sequence :(-7)10  9  2  3  8  8  1
    position : (1) 2  2  2  3  4  4  2
    LIS      : -7  2  3  8
    /* search 1st, -7 is first LIS element */
 我的代码如下:
#include <iostream>
#define SIZE 1001

using namespace std;

int main()
{
    int a[1001];
    int f[1000];
    int lis[1000];
    int i, j, n, top, temp;
    int stack[SIZE];
    cin >> n;

    top = 0;
    /* 第一个元素可能为0 */
    stack[0] = -1;
    for (i = 0; i < n; i++)
    {
        cin >> a[i];
        temp=a[i];
        /* 比栈顶元素大数就入栈 */
        if (temp > stack[top])
        {
            stack[++top] = temp;
            f[i]=top;
        }
        else
        {
            int low = 1, high = top;
            int mid;
            /* 二分检索栈中比temp大的第一个数 */
            while(low <= high)
            {
                mid = (low + high) / 2;
                if (temp > stack[mid])
                {
                    low = mid + 1;
                }
                else
                {
                    high = mid - 1;
                }
            }
            /* 用temp替换 */
            stack[low] = temp;
            f[i]=low;
        }
    }

    /* 最长序列数就是栈的大小 */
    cout << top << endl;
    int t=top;
    for(int i=n;i>=0;i--)
    {
        if(f[i]==t)
        {
              lis[--t]=a[i];
        }
         if(t<0)
            break;
    }
    for(int i=0;i<top;i++)
        cout<<lis[i]<<endl;

    
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值