动态规划算法——最长上升子序列

今天我们要讲的是最长上升子序列(LIS)

 

【题目描述】

给定N个数,求这N个数的最长上升子序列的长度

【样例输入】

7

2 5 3 4 1 7 6

【样例输出】

4

 

什么是最长上升子序列? 就是给你一个序列,请你在其中求出一段不断严格上升的部分,它不一定要连续。

就像这样:2,3,4,7和2,3,4,6就是序列2 5 3 4 1 7 6的两种选取方案。最长的长度是4.

那么,怎么求出它的最大上升子序列长度为4呢?这里介绍两种方法,都是以动态规划为基础的。

 

首先,我们先介绍较慢 O(n2)O(n2) 的方法。我们记 fifi为到这个数为止,最长上升子序列的长度。

这种方法就是每一次尝试寻找“可以接下去的”那一个数,换句话说,设原序列为a,则

aj<ai(j<i)aj<ai(j<i)且fj+1>fifj+1>fi时,fi=fj+1fi=fj+1。

对于每一个数,他都是在“可以接下去”的中,从前面的最优值+1转移而来。通俗的来说,你肯定就是在所有能找到的里面取最好的一个,不要白不要嘛。

因此,这个算法是可以求出正确答案的。复杂度很明显,外层i枚举每个数,内层j枚举目前i的最优值,即 O(n^2)

package cn.tiger.funny;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 动态规划算法——最长上升子序列
 * @author jyuan
 *
 */
public class LIS {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            list.add(i);
        }
        Collections.shuffle(list); //乱序
        System.out.println(list); 
        //[18, 8, 19, 11, 14, 16, 6, 13, 17, 12, 4, 1, 0, 3, 15, 2, 7, 10, 9, 5]
        System.out.println(lis(list));  //5
    }

    private static int lis(List<Integer> list) {
        int[] num = new int[list.size()];
        for(int i=0 ; i<list.size() ; i++) {
            num[i]=1;
            for(int j=0;j<i;j++)
            {
                if(list.get(j)<list.get(i) && num[j]>=num[i])
                       num[i]=num[j]+1;
            }
        }
        int max=0;
        for(int i=0 ; i<list.size() ; i++)
            if(max<num[i])
                max=num[i];
        return max;
    }
}

 

posted @ 2021-01-18 14:27  预言2018  阅读(63)  评论(0)    收藏  举报