LCS的两种解法比较

动态规划问题一般具有两个要素:最优子结构与子问题重叠。

通常在求解LCS问题时,我们都会用到两种方法:

1. momo-ization(备忘录方法)

利用了该问题的重叠子问题特性,而重叠子问题可以使用递归直接解决

0 A B C B D A B
0 0 0 0 0 0 0 0 0
B 0 0 1 1 1 1 1 1
D 0 0 1 1 1 2 2 2
C 0 0 1 2 2 2 2 2
A 0 1 1 2 2 2 3 2
B 0 1 2 2 3 3 3 4
A 0 1 2 2 3 3 4 4

所谓自上而下就是从下表最大处开始递归求解,最终结果为LCS(x,y,x.length,y.length);

也就是上表中从最后一格向上回溯直到哨兵的过程,在求解每个子问题之前,我们先检测一下这个子问题之前有没有算过,若果有,那么不用计算直接返回结果,如果没有,那么就计算这个子问题,之后将结果保存起来,方便下次再遇到时使用。。

时间复杂度T(n) = O(mn);

空间复杂度S = O(mn);//二维数组

[java] view plaincopy
01.public class TTBlcs { 
02.    static int[][] c = new int[100][100]; 
03.    static int NIF = 9999; 
04.    public static void main(String[] args) {         
05.        char[] x = {‘A‘,‘B‘,‘C‘,‘B‘,‘D‘,‘A‘,‘B‘}; 
06.        char[] y = {‘B‘,‘D‘,‘C‘,‘A‘,‘B‘,‘A‘}; 
07.         
08.        //TTBlcs t = new TTBlcs(); 
09.        for(int i = 0;i <= x.length;i++){//周围有一圈哨兵均为0 
10.            for(int j = 0;j <= y.length;j++) 
11.            { 
12.                c[i][j] = NIF; 
13.            } 
14.        } 
15.        System.out.print(LCS(x,y,x.length,y.length));//自上而下 
16.    } 
17.     
18.    public static int LCS(char[] x,char[] y,int i,int j){ 
19.        if(c[i][j] < NIF)//记录如果算出来便直接返回(备忘) 
20.            return c[i][j]; 
21.        if((i == 0)||(j == 0)){ 
22.            c[i][j] = 0; 
23.        } 
24.        else if(x[i-1] == y[j-1]) 
25.                c[i][j] = LCS(x,y,i-1,j-1) + 1; 
26.        else  
27.                c[i][j] = LCS(x,y,i-1,j) >= LCS(x,y,i,j-1)? LCS(x,y,i-1,j):LCS(x,y,i,j-1); 
28.        return c[i][j]; 
29.    } 
30. 
31.}

2. 动态规划DP:

所谓自下而上,就是从下标(1,1)处开始求解的过程,不过省去了递归的过程,自下而上的构建原问题的解,首先求解最基本的情况,再从最基本的情况一部一部的向上求解,比如我要求解[2…4],那么我首先需要知道[2…2][3…4]和[2…3][4…4]的最优解,需要知道[3…4],那么首先需要知道[3…3][4…4]的最优解,所以,倒不如我们将原问题需要的解先构建出来,再慢慢向上一层一层的构建,最后组成原问题的解!。

时间复杂度T(n) = O(mn);

空间复杂度S = O(mn);//二维数组

[java] view plaincopy
01.public class BTTlcs { 
02.    static int[][] c = new int[100][100]; 
03.    public static void main(String[] args) { 
04.        char[] x = {‘A‘,‘B‘,‘C‘,‘B‘,‘D‘,‘A‘,‘B‘}; 
05.        char[] y = {‘B‘,‘D‘,‘C‘,‘A‘,‘B‘,‘A‘}; 
06.        for(int k = 0;k <= x.length;k++) 
07.        { 
08.            c[0][k] = 0; 
09.        } 
10.        for(int k = 0;k <= y.length;k++) 
11.        { 
12.            c[k][0] = 0; 
13.        } 
14.        LCS(x,y); 
15.    } 
16.     
17.    public static void LCS(char[] x,char[] y){ 
18.        for(int i = 1;i <= x.length;i++) 
19.        { 
20.            for(int j = 1;j <= y.length;j++) 
21.            { 
22.                if(x[i-1] == y[j-1]) 
23.                    c[i][j] = c[i-1][j-1] + 1; 
24.                else  
25.                    c[i][j] = c[i-1][j] >= c[i][j-1]?c[i-1][j]:c[i][j-1]; 
26.            } 
27.        } 
28.        for(int i = 0;i <= x.length;i++) 
29.        { 
30.            for(int j = 0;j<y.length;j++) 
31.            { 
32.                System.out.print(c[i][j]); 
33.            } 
34.            System.out.print("\n"); 
35.        } 
36.        System.out.print(c[x.length][y.length]); 
37.    } 
38.}

自上而下的优点是并不需要求解每一个子问题的解,而是只求解有需要的子问题的解,缺点就是需要递归调用,函数调用浪费时间。
自下而上的优点是并不需要递归调用,每个子问题求解的速度较快,缺点每个子问题都要计算,就算这个子问题的解对原问题的解并没有任何帮助!

时间: 2024-07-30 03:20:11

LCS的两种解法比较的相关文章

hdu 4521 小明系列问题——小明序列 (间隔至少为d的LIS 两种解法)

先附上资源地址:http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html 进程(process)和线程(thread)是操作系统的基本概念,但是它们比较抽象,不容易掌握. 最近,我读到一篇材料,发现有一个很好的类比,可以把它们解释地清晰易懂. 1. 计算机的核心是CPU,它承担了所有的计算任务.它就像一座工厂,时刻在运行. 2. 假定工厂的电力有限,一次只能供给一个车间使用.也就是说,一个车间开工的时候,其他车间都必须停工

POJ 1515 Street Directions --一道连通题的双连通和强连通两种解法

题意:将一个无向图中的双向边改成单向边使图强连通,问最多能改多少条边,输出改造后的图. 分析: 1.双连通做法: 双连通图转强连通图的算法:对双连通图进行dfs,在搜索的过程中就能按照搜索的方向给所有边定向,其中桥不能改造,只能保留双向边. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #includ

求最大公约数的两种解法(欧几里得算法和素数分解)

最大公约数的两种解法(欧几里得算法和素数分解) 方法一: 欧几里得算法,又称辗转相除法 定理(欧几里得算法):设a和b是正整数,则存在最大求最大公因子d=(a,b)的一种算法,且存在求一组整数s,t使得d = sa+tb 举个例子:求168和60的最大公约数? 168 = 2 * 60 + 48 60  = 1 * 48 +12 48  = 4 * 12 由此得最大公约数为12 关于最大公倍数 C语言程序代码:很简单就不加注释了 #include<stdio.h> #define SWAP(a

POJ 3628 Bookshelf 2 0/1背包和DFS两种解法

题目链接:POJ 3628 Bookshelf 2 Bookshelf 2 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7462   Accepted: 3436 Description Farmer John recently bought another bookshelf for the cow library, but the shelf is getting filled up quite quickly,

统计逆序对的两种解法

统计逆序对的两种解法 归并排序(mergeSort) 逆序对定义 \(i<j\) 但\(a[i]>a[j]\),假设我们分别使得通过mergeSort使得左右半边有序 即\(a[1]...a[mid]\) 递增, \(a[mid+1]....a[n]\)递增,我们需要通过merge操作,完成整个的排序和新增逆序对的计数,较小值出现在左半边记为 a[i],出现在右半边即为 a[j],那么每次出现在右半边,意味左半边比a[i]大的数都比a[j]大,由此可以统计逆序对 HDU1394 代码实现 #i

Letter Combinations of a Phone Number:深度优先和广度优先两种解法

Letter Combinations of a Phone Number Given a digit string, return all possible letter combinations that the number could represent. A mapping of digit to letters (just like on the telephone buttons) is given below. Input:Digit string "23" Outpu

【动态规划】01背包问题_两种解法

问题描述 0-1背包问题:给定\(n\)种物品和一背包.物品i的重量是\(w_i\),其价值为\(v_i\),背包的容量为\(C\).问:应该如何选择装入背包的物品,使得装人背包中物品的总价值最大? 在选择装人背包的物品时,对每种物品\(i\)只有两种选择,即装人背包或不装入背包.不能将物品\(i\)装入背包多次,也不能只装入部分的物品\(i\).因此,该问题称为0-1背包问题. 此问题的形式化描述是,给定\(C>0\),\(w_i>0\),\(v_i>0\),\(1≤i≤n\),要求找

涨姿势题2_水题_两种解法

Problem Description 涨姿势题就是所谓的优化题,在组队赛中,队伍发现了一题水题,那么应该交给谁去处理?作为处理水题的代码手,应该具备什么样的素养?1,要快,水题拼的就是速度!2,不能卡水题!水题都卡,绝对不是一个代码手的风范!3,不能出错,错一次即罚时20分钟,对于水题来讲是致命的!4,要能看出来一题是水题!没有这条,上面三条都是没有意义的! 如果你希望你成团队中一个合格的代码手,那么这套题是你最好的选择,快AC吧! 本系列即是为了提高水题代码手的素养而准备的!水题经常需要用到

ZOJ3822 ACM-ICPC 2014 亚洲区域赛牡丹江赛区现场赛D题Domination 概率DP(两种解法)

题目地址:点击打开链接 这道题有两种做法,第一种是直接求期望,类似于poj 2096 区别在于这个步数有限.所以要迭代步数. #include <cstdio> #include <cstring> #include <iostream> #define maxn 55//这里刚开始写成了50+10 那么maxn*maxn就会小很多wa了一次 using namespace std; double dp[maxn][maxn][maxn*maxn]; int N,M,T