最长公共子序列问题---动态规划

最长递增子序列问题是一个很基本、较常见的小问题,但这个问题的求解方法却并不那么显而易见,需要较深入的思考和较好的算法素养才能得出良好的算法。由于这个问题能运用学过的基本的算法分析和设计的方法与思想,能够锻炼设计较复杂算法的思维,我对这个问题进行了较深入的分析思考,得出了几种复杂度不同算法,并给出了分析和证明。

一,    最长递增子序列问题的描述

设L=<a1,a2,…,an>是n个不同的实数的序列,L的递增子序列是这样一个子序列Lin=<aK1,ak2,…,akm>,其中k1<k2<…<km且aK1<ak2<…<akm。求最大的m值。

二,    第一种算法:转化为LCS问题求解

设序列X=<b1,b2,…,bn>是对序列L=<a1,a2,…,an>按递增排好序的序列。那么显然X与L的最长公共子序列即为L的最长递增子序列。这样就把求最长递增子序列的问题转化为求最长公共子序列问题LCS了。

最长公共子序列问题用动态规划的算法可解。设Li=< a1,a2,…,ai>,Xj=< b1,b2,…,bj>,它们分别为L和X的子序列。令C[i,j]为Li与Xj的最长公共子序列的长度。则有如下的递推方程:

这可以用时间复杂度为O(n2)的算法求解,由于这个算法上课时讲过,所以具体代码在此略去。求最长递增子序列的算法时间复杂度由排序所用的O(nlogn)的时间加上求LCS的O(n2)的时间,算法的最坏时间复杂度为O(nlogn)+O(n2)=O(n2)。

三,    第二种算法:动态规划法

设f(i)表示L中以ai为末元素的最长递增子序列的长度。则有如下的递推方程:

这个递推方程的意思是,在求以ai为末元素的最长递增子序列时,找到所有序号在L前面且小于ai的元素aj,即j<i且aj<ai。如果这样的元素存在,那么对所有aj,都有一个以aj为末元素的最长递增子序列的长度f(j),把其中最大的f(j)选出来,那么f(i)就等于最大的f(j)加上1,即以ai为末元素的最长递增子序列,等于以使f(j)最大的那个aj为末元素的递增子序列最末再加上ai;如果这样的元素不存在,那么ai自身构成一个长度为1的以ai为末元素的递增子序列。

public void lis(float[] L)
  {
         int n = L.length;
         int[] f = new int[n];//用于存放f(i)值;
         f[0]=1;//以第a1为末元素的最长递增子序列长度为1;
         for(int i = 1;i<n;i++)//循环n-1次
         {
                f[i]=1;//f[i]的最小值为1;
                for(int j=0;j<i;j++)//循环i 次
                {
                       if(L[j]<L[i]&&f[j]>f[i]-1)
                              f[i]=f[j]+1;//更新f[i]的值。
                }
         }
         System.out.println(f[n-1]);
  }

最长公共子序列1---求最长公共子序列的长度:

给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱)
例如:给定一个长度为8的数组A{1,3,5,2,4,6,7,8},则其最长的单调递增子序列为{1,2,4,6,7,8},长度为6.

输入描述:

第一行包含一个整数T,代表测试数据组数。
对于每组测试数据:
N-数组的长度
a1 a2 ... an (需要计算的数组)
保证:
1<=N<=3000,0<=ai<=MAX_INT.

输出描述:

对于每组数据,输出一个整数,代表最长递增子序列的长度。

输入例子:

2
7
89 256 78 1 46 78 8
5
6 4 8 2 17

解题思路:采用动态规划的方法来解,如下:
数组array     ai 89 256 78 1 46 78 8
长度list     len(ai) 1 2 1 1 2 3 2


import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int T = scan.nextInt();
//        System.out.println(T);
        for(int i=0;i<T;i++){
            int N = scan.nextInt();
//            System.out.println(N);
            int[] num = new int[N];
            for(int j=0;j<N;j++){
                num[j] = scan.nextInt();
            }
           System.out.println(lengthOfMaxSubIncreaseArray(num, N));
        }
    }

    public static int lengthOfMaxSubIncreaseArray(int[] array, int n){
        if(n==1){
            return 1;
        }
        int maxLen = 0;
        int[] list = new int[n];
        for(int i=0;i<n;i++){
            list[i]=1;
            for(int j=0;j<i;j++){
                if(array[j]<array[i]&&list[j]+1>list[i]){
                    list[i] = list[j]+1;
                }
            }
        }
        for(int i=0;i<n;i++){
            if(list[i]>maxLen)
                maxLen = list[i];
        }
        return maxLen;
    }
}

最长公共子序列2----求最长公共子序列的第一组序列:

给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱)
例如:给定一个长度为8的数组A{1,3,5,2,4,6,7,8},则其最长的单调递增子序列为{1,2,4,6,7,8},长度为6.

输入描述:

第一行包含一个整数T,代表测试数据组数。
对于每组测试数据:
N-数组的长度
a1 a2 ... an (需要计算的数组)
保证:
1<=N<=3000,0<=ai<=MAX_INT.

输出描述:

对于每组数据,输出一个整数序列,代表最长递增子序列。
若有多组最长上升子序列,输出第一组。
保证:1<=T<=20,1<=N<=3000,0<=ai<=MAX_INT.

输入例子:

2
7
89 256 78 1 46 78 8
5
6 4 8 2 17

输出例子:

1 46 78
6 8 17
时间: 2024-10-11 16:23:38

最长公共子序列问题---动态规划的相关文章

nyist oj 36 最长公共子序列 (动态规划基础题)

最长公共子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 咱们就不拐弯抹角了,如题,需要你做的就是写一个程序,得出最长公共子序列. tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列. 输入 第一行给出一个整数N(0<N<100)表示待测数据组数 接

最长公共子序列(动态规划)

#include<iostream> #include<vector> #include<iterator> #include<algorithm> #include<string> using namespace std; /* *最长公共子序列(动态规划) */ vector<vector<int>> c;//c[i][j]记录串a[0..i]与串b[0..j]之间的最长公共子序列的长度 vector<vecto

LCS问题(最长公共子序列)-动态规划实现

问题描述: 问题] 求两字符序列的最长公共字符子序列 注意: 并不要求子串(字符串一)的字符必须连续出现在字符串二中. 思路分析: 最优子结构和重叠子问题的性质都具有,所以要采取动态规划的算法 最长公共子序列的结构 设序列X= 其中Xm-1= 子问题的递归结构 由最长公共子序列问题的最优子结构性质可知,要找出X= 由此递归结构容易看到最长公共子序列问题具有子问题重叠性质. 例如,在计算X和Y的最长公共子序列时,可能要计算出X和Yn-1及Xm-1和Y的最长公共子序列.而这两个子问题都包含一个公共子

最长公共子序列_动态规划

具体问题的描绘和分析如下 从上图可知,要构造两个二维数组,数组L用来求各种取值的子最长公共子序列,则最后一个元素就是最长公共子序列的长度,从右边的二维表,数值为1,则就是公共的元素,我们用数组记录下来, 代码如下: 1 #include<bits/stdc++.h> 2 using namespace std; 3 int Maxson(int m,int n,char array[],char array1[],int L[][100],int s[][100],char z[]) 4 {

求序列1和序列2的最长公共子序列-基于动态规划方法

1 #include <cstdlib> 2 #include <iostream> 3 #include <cstring> 4 5 using namespace std; 6 7 class maxlen_string 8 { 9 public: 10 void string_(); 11 void LCSLength(int,int,char*,char*,int**,int**); 12 void LCS(int,int,char*,int**); 13 ~m

HDU 1159 Common Subsequence (动态规划、最长公共子序列)

Common Subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 55301    Accepted Submission(s): 25537 Problem Description A subsequence of a given sequence is the given sequence with some el

最长公共子序列python实现

最长公共子序列是动态规划基本题目,下面按照动态规划基本步骤解出来. 1.找出最优解的性质,并刻划其结构特征 序列a共有m个元素,序列b共有n个元素,如果a[m-1]==b[n-1],那么a[:m]和b[:n]的最长公共子序列长度就是a[:m-1]和b[:n-1]的最长公共子序列长度+1:如果a[m-1]!=b[n-1],那么a[:m]和b[:n]的最长公共子序列长度就是MAX(a[:m-1]和b[:n]的最长公共子序列长度,a[:m]和b[:n-1]的最长公共子序列长度). 2.递归定义最优值

动态规划-最长公共子序列

(1).问题描述:给出2个序列,x是从1到m,y是从1到n,找出x和y的最长公共子序列? x:A B C B D A B y:B D C A B A 则:最长公共子序列长度为4,BDAB BCAB BCBA均为LCS(最长公共子序列): 模型实现图: (2).问题解决 代码实现了最长公共子序列的长度 #include<stdio.h> #define N    10 int LCS(int *a, int count1, int *b, int count2); int LCS(int *a,

动态规划 - 最长公共子序列(LCS)

最长公共子序列也是动态规划中的一个经典问题. 有两个字符串 S1 和 S2,求一个最长公共子串,即求字符串 S3,它同时为 S1 和 S2 的子串,且要求它的长度最长,并确定这个长度.这个问题被我们称为 最长公共子序列问题. 与求最长递增子序列一样,我们首先将原问题分割成一些子问题,我们用 dp[i][j]表示 S1 中前 i 个字符与 S2 中前 j 个字符分别组成的两个前缀字符串的最 长公共子串长度. 显然的,当 i. j 较小时我们可以直接得出答案,如 dp[0][j]必 等于 0.那么,