比较动态规划和递归两种算法求最长公共子序列的运行时间,并分析递归算法效率低的原因。
时间: 2024-04-09 10:30:02 浏览: 12
动态规划和递归是两种常见的算法用于求解最长公共子序列(Longest Common Subsequence)问题。
动态规划算法的运行时间为O(m * n),其中m和n分别为两个输入序列的长度。动态规划算法使用一个二维数组来保存中间结果,通过填表的方式依次计算出所有子问题的解,直到得到最终结果。由于每个子问题只需要计算一次,并且在计算当前子问题时,它所依赖的子问题的结果已经计算出来了,因此动态规划算法具有较好的时间复杂度。
递归算法的运行时间为指数级别,即O(2^(m+n))。递归算法是通过将原问题划分为更小的子问题来求解,但是在递归过程中会产生大量的重复计算。例如,在求解最长公共子序列时,如果两个序列的最后一个元素相同,则可以将问题转化为求解去掉最后一个元素的两个子序列的最长公共子序列;如果两个序列的最后一个元素不同,则可以分别求解去掉其中一个序列的最长公共子序列。但是递归算法没有记录已经计算过的子问题的结果,导致相同的子问题会被重复计算,从而降低了效率。
因此,递归算法的效率低主要是由于重复计算导致的。而动态规划算法通过保存中间结果避免了重复计算,因此具有更高的效率。
相关问题
C语言分别用动态规划算法和递归算法求最长公共子序列并输出最长公共子序列
当使用动态规划算法和递归算法来求解最长公共子序列(Longest Common Subsequence)时,可以按照以下步骤进行实现:
1. 动态规划算法(Dynamic Programming):
```c
#include <stdio.h>
#include <string.h>
int max(int a, int b) {
return (a > b) ? a : b;
}
void printLCS(char *str1, char *str2, int m, int n, int dp[m+1][n+1]) {
int length = dp[m][n];
char lcs[length + 1];
lcs[length] = '\0';
int i = m, j = n;
while (i > 0 && j > 0) {
if (str1[i - 1] == str2[j - 1]) {
lcs[length - 1] = str1[i - 1];
i--;
j--;
length--;
}
else if (dp[i-1][j] > dp[i][j-1]) {
i--;
}
else {
j--;
}
}
printf("Longest Common Subsequence: %s\n", lcs);
}
void LCS(char *str1, char *str2) {
int m = strlen(str1);
int n = strlen(str2);
int dp[m+1][n+1];
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= n; j++) {
if (i == 0 || j == 0) {
dp[i][j] = 0;
}
else if (str1[i - 1] == str2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
}
else {
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
}
printLCS(str1, str2, m, n, dp);
}
int main() {
char str1[] = "AGGTAB";
char str2[] = "GXTXAYB";
LCS(str1, str2);
return 0;
}
```
2. 递归算法:
```c
#include <stdio.h>
#include <string.h>
int max(int a, int b) {
return (a > b) ? a : b;
}
void printLCS(char *str1, char *str2, int m, int n, int dp[m+1][n+1]) {
if (m == 0 || n == 0) {
return;
}
if (str1[m - 1] == str2[n - 1]) {
printLCS(str1, str2, m - 1, n - 1, dp);
printf("%c", str1[m - 1]);
}
else if (dp[m-1][n] > dp[m][n-1]) {
printLCS(str1, str2, m - 1, n, dp);
}
else {
printLCS(str1, str2, m, n - 1, dp);
}
}
int LCS(char *str1, char *str2, int m, int n) {
if (m == 0 || n == 0) {
return 0;
}
if (str1[m - 1] == str2[n - 1]) {
return 1 + LCS(str1, str2, m - 1, n - 1);
}
else {
return max(LCS(str1, str2, m - 1, n), LCS(str1, str2, m, n - 1));
}
}
int main() {
char str1[] = "AGGTAB";
char str2[] = "GXTXAYB";
int m = strlen(str1);
int n = strlen(str2);
int dp[m+1][n+1];
int lcsLength = LCS(str1, str2, m, n);
printf("Longest Common Subsequence Length: %d\n", lcsLength);
printLCS(str1, str2, m, n, dp);
return 0;
}
```
这样,你就可以使用动态规划算法和递归算法求解最长公共子序列,并输出最长公共子序列。
1. 用动态规划算法求最长公共子序列; 用递归算法求最长公共子序列;
1. 使用动态规划算法求解最长公共子序列(Longest Common Subsequence, LCS)问题的步骤如下:
假设有两个序列,分别为序列A和序列B,长度分别为m和n。
- 创建一个二维数组dp,大小为(m+1)×(n+1),用于记录最长公共子序列的长度。
- 初始化第一行和第一列的值为0。
- 从第二行和第二列开始,依次遍历序列A和序列B的每个元素:
- 如果A[i-1]和B[j-1]相等,则dp[i][j] = dp[i-1][j-1] + 1;
- 否则,dp[i][j] = max(dp[i-1][j], dp[i][j-1]),即取左边或上边的最大值。
- 最终,dp[m][n]即为最长公共子序列的长度。
可以根据dp数组的记录,反向回溯得到最长公共子序列。
2. 使用递归算法求解最长公共子序列问题的思路如下:
假设有两个序列,分别为序列A和序列B,长度分别为m和n。
- 如果任一序列为空,则最长公共子序列长度为0。
- 如果A[m-1]和B[n-1]相等,则最长公共子序列长度为1加上A[0...m-2]和B[0...n-2]的最长公共子序列长度。
- 否则,最长公共子序列长度为A[0...m-2]和B[0...n-1]的最长公共子序列长度与A[0...m-1]和B[0...n-2]的最长公共子序列长度的较大值。
通过递归的方式,可以依次缩小问题规模,直至问题规模为0,返回结果。但是由于存在重复计算的子问题,递归算法的效率较低,可以通过记忆化搜索或动态规划进行优化。