ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

LCS问题动态规划方法的改进:时间复杂度O(mn*(min(m,n))),空间复杂度O(1)

2022-02-02 14:03:37  阅读:179  来源: 互联网

标签:ch LCS min int 复杂度 DP string


LCS问题,即求两个字符串的最长公共子序列的问题。该问题常用的解法有普通递归法和动态规划法。

  • 普通递归法方法采用了减而治之和分而治之的思想。但该算法存在大量子问题的重复计算,其时间复杂度为指数时间复杂度。
  • DP方法使用一个二维数组记录每个子问题的结果,从而避免了子问题的重复计算,只需要根据一定的次序,如从底向上,从只有一个字符出发,一次填满该数组,最后的DP[m][n]即为该问题的结果,同时可以根据DP数组将一个解结果还原。其时间复杂度和空间复杂度都为 \(\Theta(mn)\)。

在对DP数组观察的基础上,笔者对动态规划法进行了改进。现一个具体实例来讲解如何改进动态规划法。
两个字符串分别为"EDUCATIONAL"和"ADVANTAGE",求这两个字符串的最长公共子序列,其DP数组如下图所示:
image
可以观察到最长公共子序列的一个解为DATA,对应的相同的字母,以A为例,是A在第一个字符串和第二个字符串的位置和最小的这个字母,对于剩下的字母也是如此,因此我们可以采用这样的策略来找到个一个LSC的解,即寻找两个字符串中相同的字符,记录下该字符在两个字符串中的位置,当这两个位置和最小时,该字符就是最长公共子序列的第一个字符,记录下这个字符的坐标,用ir和jr表示,第二次循环从ir+1和jr+1处开始搜索,得到最长公共子序列的第二个字符,依次类推。
编写程序的过程中,需要考虑到重复的字母,这里使用了一个函数来统计该字母在LSC解中,出现的次数,来查找该字母在两个字符串中的位置。
循环结束的条件是两个坐标之和有一个初始值minpos,当该minpos的初始值不改变时,说明寻找不到新的满足条件的字母,则循环终止。其时间复杂度为\(\O(mn*min(n,n))\),空间复杂度为\(\O(1)\),程序如下:

// LCS_DP_improve.cpp -- 优化LCS的DP解法,使空间复杂度为常数复杂度,同时得到LCS的组成
// 课后作业3
// 空间复杂度O(1)时间复杂度O(mn*min(m,n))
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
using std::string;

int timeschar(string s, char ch);               // 计算ch在s中出现的次数
int searchpos(string s, char ch, int n);        // 计算第n个ch出现的位置
int LCS_DP_improve(string A, string B, string & C);

int main()
{
    using namespace std;
    string str1 = "immaculate";
    string str2 = "computer";
    string str;
    int len = LCS_DP_improve(str1, str2, str);
    cout << str << endl;
    cout << "Length: " << len << endl;
    return 0;
}
int timeschar(string s, char ch)
{
    int len = s.size();
    int times = 0;
    for (int i = 0; i < len; i++)
        if (s[i] == ch)
            times++;
    return times;
}
int searchpos(string s, char ch, int n)
{
    int len = s.size();
    int timesch = 0;
    for (int i = 0; i < len; i++)
        if (s[i] == ch)
        {
            timesch++;
            if (timesch == n)
                return i;
        }
    return -1;          // 没有找到,本问题不存在
}
int LCS_DP_improve(string A, string B, string & C)
{
    int lenA = A.size();
    int lenB = B.size();
    int minlen = lenA > lenB ? lenB : lenA; // 计算A和B的最小长度
    int ir = -1;     // 每次喜欢开始的位置
    int jr = -1;     // 同ir
    string tempA;    // 记录每次寻找的位置
    for (int k = 0; k < minlen; k++)
    {
        int minpos = lenA + lenB;         // 记录相等时最小的x,y的坐标,初始为最大值
        char ch;    //记录找到的字母
        for (int i = ir + 1; i < lenA; i++)
            for (int j = jr + 1; j < lenB; j++)
                if(A[i] == B[j])
                {
                    if (minpos > i + j)
                    {
                        minpos = i + j;
                        ch = A[i];
                    }
                }
        if (minpos == lenA + lenB)      // 终止循环的条件
            break;
        C.push_back(ch);
        int timech = timeschar(C, ch);
        ir = searchpos(A, ch, timech);
        jr = minpos - ir;
    }
    return C.size();
}

标签:ch,LCS,min,int,复杂度,DP,string
来源: https://www.cnblogs.com/Fight-go/p/15860248.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有