最长上升子序列

原文地址 http://www.daileinote.com/computer/math/0d​​​​​​​

 

最长上升子序列(Longest Increasing Subsequence),简称 LIS,即在一个给定的数值序列中,找到一个子序列,使得这个子序列元素的数值依次递增,并且这个子序列的长度尽可能地大。最长递增子序列中的元素在原序列中不一定是连续的,比如

{0, 8, 4, 12, 2, 10}
最长上升子序列为
0, 4, 10 - 长度为 3

{34,2,4,33,32,35}
最长上升子序列为
2,4,32,35 - 长度为 4

{4}
最长上升子序列为
4 - 长度为 1

算法实现

假设长度为 n 的数组 arr,这里的 i 代表 arr[i] 即为子序列结尾元素
L(i) = 1 + max(L(j)) 需要满足 0 < j < i 且 arr[j] < arr[i]
L(i) = 1 如果 j 不存在

比如

求 arr[] = {50,33,34,40,1} 的最长上升子序列长度
即求解 MAX( L(1),L(2),L(3),L(4),L(5) )
L(1) = 1
L(2) = 1 (因为50 > 33 即 j 不存在)
L(3) = 1 + MAX( L(2) ) = 2 因为 50 > 34

L(4) = 1 + MAX( L(3), L(2) ) 因为 50 > 40
由上可值 L(3) = 2, L(2) = 1 即 MAX( L(3), L(2) ) == 2
即L(4) = 1+2 = 3

L(5) = 1

可得 MAX( L(1),L(2),L(3),L(4),L(5) ) = L(4) = 3
即arr最长上升子序列长度为3

 

例子-1

#include <stdio.h>

int lis(int *arr, int n) 
{ 
    int i,res,max = 1;

    if (n == 1) return 1;

    for (i = 1; i < n; i++) {
        // 过滤掉不比自己小的
        if (arr[i - 1] >= arr[n - 1])
            continue;
        res = lis(arr, i);
        // found
        if (res + 1 > max)
            max = res + 1;
    }

    return max;
} 

int main()
{
    int arr[] = {34,2,4,33,32,35};
    int n = sizeof(arr) / sizeof(int);
    printf("length of lis is %d\n", lis(arr, n));
    return 0;
}

上面解法包含重叠子问题,下面是一个求长度为4的数组的LIS长度,可以看出出现了很多重复

              lis(4)
        /        |      \
      lis(3)    lis(2)   lis(1)
     /     \      |
   lis(2) lis(1) lis(1)
   /
lis(1)

 

例子-2

下面是利用表格法(tabular method)实现,可以去除重叠子问题请参考 http://www.daileinote.com/computer/math/0d

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值