算法第三章上机实践报告,编辑距离问题

实践报告任选一题进行分析。内容包括:

  1. 实践题目
  2. 问题描述
  3. 算法描述
  4. 算法时间及空间复杂度分析(要有分析过程)
  5. 心得体会(对本次实践收获及疑惑进行总结)

1.实践题目

7-3 编辑距离问题 (30 分)

2.问题描述

设A和B是2个字符串。要用最少的字符操作将字符串A转换为字符串B。这里所说的字符操作包括 (1)删除一个字符; (2)插入一个字符; (3)将一个字符改为另一个字符。 将字符串A变换为字符串B所用的最少字符操作数称为字符串A到 B的编辑距离,记为d(A,B)。 对于给定的字符串A和字符串B,计算其编辑距离 d(A,B)。

输入格式:

第一行是字符串A,文件的第二行是字符串B。

提示:字符串长度不超过2000个字符。

输出格式:

输出编辑距离d(A,B)

输入样例:

在这里给出一组输入。例如:

fxpimu
xwrs 

输出样例:

在这里给出相应的输出。例如:

5


3.算法描述

这道题是类似于最长子串匹配的题目,不过要更深入一些,首先令m[a][b]为 字符串s1下标从0到a-1组成的字符串 与 字符串从s2下标0到b-1组成的字符串的最优编辑距离,接着用动态规划的思想分析m[a][b]与它的子问题是什么关系。通过分析,我们能分析出m[a][b]的表达式:

当s1[a-1] = s2[b-1] 当字符串s1[a-1]和s2[b-1]相等时,则不用对末位s1[a-1]和s2[b-1]进行修改操作,此时m[a][b]最优编辑距离 = m[a-1][b-1]

当s1[a-1] != s2[b-1]时, 这时有三种情况

  1.删除末位s1[a-1]和s2[b-1],以使之s1末位与或s2末位相等,只进行一次删除操作,操作数+1,此时s1和s2的末尾元素已经相等, 只需要比较s1的前a个元素与s2的前b-1个元素,或者比较s1的前a-1个元素与s2的前b个元素,因此此时m[a][b]最优编辑距离 = m[a-1][b] + 1 或者 m[a][b-1] + 1

  2.增添一位到末位s1[a-1]和s2[b-1],使之s1末位与或s2末位相等,只进行一次增添操作,操作数+1,同理,此时m[a][b]最优编辑距离 = m[a][b-1] + 1 或者 m[a-1][b] + 1 

  3.修改一位末位s1[a-1]和s2[b-1],使之s1末位与或s2末位相等,只进行一次增添操作,操作数+1,此时s1和s2的末尾元素已经相等, 只需要比较s1的前a-1个元素与s2的前b-1个元素,则m[a][b]最优编辑距离 = m[a-1][b-1] + 1

通过分析可以知道m[a][b]与上,左,左上元素有关,因此可以用自上而下,从左到右的填表方式填表,从而列出递推式:

for (int i = 1; i <= b.size(); i++) {
        for (int j = 1; j <= a.size(); j++) {
            if (a[j - 1] == b[i - 1]) {
                m[i][j] = m[i - 1][j - 1];
            }
            else {
                m[i][j] = 1 + min(min(m[i - 1][j], m[i][j - 1]), m[i - 1][j - 1]);
            }
            
        }
    }

继续分析发现,这个二维数组m需要初始化,边界是行、列为0的时候,

具体化分析:

  此时有s1=“ab" , s2="" , 求m[2][0],当s2为空时, m[2][0] = 2,只要把s2进行s1字符串长度次添加操作就能将s2改为s1。

  同理有s1="",s2=”abc",求m[0][3],同上分析有m[0][3] = 3

归纳总结有:

  m[i][0] = i

  m[0][j] = j

综上可以写出初始化+递推过程公式:

for (int i = 0; i <= b.size(); i++) {
        for (int j = 0; j <= a.size(); j++) {
            if (i == 0) {
                m[i][j] = j;
            }
            else if (j == 0) {
                m[i][j] = i;
            }
            else {
                if (a[j - 1] == b[i - 1]) {
                    m[i][j] = m[i - 1][j - 1];
                }
                else {
                    m[i][j] = 1 + min(min(m[i - 1][j], m[i][j - 1]), m[i - 1][j - 1]);
                }
            }
        }
    }

最后,结果就保存在m[][]的最右下角

完整代码

int min(int a, int b) {
    return a < b ? a : b;
}


int main(){
    string a;
    string b;
    cin >> a;
    cin >> b;

    //初始化矩阵
    
    int row = 2001;
    int column = 2001;
    int **m;
    m = (int **)malloc(sizeof(int *) * row);//分配指针数组,计算行的大小
    for (int i = 0; i < row; i++)
    {
        m[i] = (int *)malloc(sizeof(int) * (column));//分配每个指针所指向的数组,再计算列
    }
    


    for (int i = 0; i <= b.size(); i++) {
        for (int j = 0; j <= a.size(); j++) {
            if (i == 0) {
                m[i][j] = j;
            }
            else if (j == 0) {
                m[i][j] = i;
            }
            else {
                if (a[j - 1] == b[i - 1]) {
                    m[i][j] = m[i - 1][j - 1];
                }
                else {
                    m[i][j] = 1 + min(min(m[i - 1][j], m[i][j - 1]), m[i - 1][j - 1]);
                }
            }
        }
    }

    cout << m[b.size()][a.size()];
}

4.算法时间及空间复杂度分析(要有分析过程)

时间复杂度分析:很简单,两层for循环,时间复杂度为O(n^2)

空间复杂度,借助了一个n×n的二维数组,空间复杂度也为O(n^2)

5.心得体会

这是一道很标准的动态规划问题,重点在于列出递归方程式,只要列出了递归公式,动态规划的题目就迎刃而解。

猜你喜欢

转载自www.cnblogs.com/likeghee/p/11695827.html