算法第三章上机实践报告
1.实践题目
2.问题描述
这道题要求从一个字符串变为另一字符串,一次最小的操作可以是增加一个字符,减少一个字符,或者将一个字符变为另外一个,每进行一次,距离加一,最小的距离,也就是最少操作次数即为所求。
3.算法描述
这道题要用到动态规划思想,类似于LCS算法:
设A,B字符串长度分别为m,n,数组c[m + 1][n + 1]记录距离,其中c[m][n]即为所求最终距离
(一).若A,B末位字符一样,则该位置的字符一定不用操作,该问题与A,B除去末位字符的子问题相同,c[m][n]=c[m - 1][n - 1];
(二).若末尾字符不一样,
(1).对A末位进行删除,则此时c[m][n] = c[m - 1][n] + 1;
(2).对A末位进行增添,增添的字符为B的末位,此时A有m + 1位而B有n位,但是末位相同,同理于(一),c[m][n] = c[m][n - 1] + 1
(三).当A为空时,相当于A增加n个字符,c[0][n] = n;
当B为空时,相当于A删除m个字符,c[m][0] = m;
当两者均为空,则无需操作c[0][0] = 0;
所以记录的数组应该是:
当i = j = 0时,c[i][j] = 0;
当i = 0, j > 0时,c[i][j] = c[0][j] = j;
当i > 0, j = 0时,c[i][j] = c[i][0] = i;
当i > 0, j > 0时,c[i][j] = min(c[m - 1][n] + 1, c[m][n - 1] + 1, c[m - 1][n - 1] + ifLastDigitEqual);
当A[i - 1] == B[j - 1](末位字符相等)时,ifLastDigitEqual = 0,否则为1;
c[m][n]即为所求
代码如下:
#include<iostream> #include<string> #include <algorithm> using namespace std; int main() { string A, B; getline(cin, A); getline(cin, B); int i, j; int ifLastDigitEqual; //记录末位字符是否相等 int **c; //记录表 c = new int*[A.length() + 1]; for (int k = 0; k <= A.length(); k++) { c[k] = new int[B.length() + 1]; } for (i = 0; i <= A.length(); i++)//B为空的情况 { c[i][0] = i; } for (j = 1; j <= B.length(); j++)//A为空的情况 { c[0][j] = j; } for (i = 1; i <= A.length(); i++) for (j = 1; j <= B.length(); j++) { if (A[i - 1] == B[j - 1]) { ifLastDigitEqual = 0; } else { ifLastDigitEqual = 1; } c[i][j] = min(c[i - 1][j] + 1, c[i][j - 1] + 1); c[i][j] = min(c[i][j], c[i - 1][j - 1] + ifLastDigitEqual); } cout << c[A.length()][B.length()]; return 0; }
4.算法时间及空间复杂度分析
用两层for循环来建表得到答案c[m][n],时间复杂度为O(n^2),建表需要m * n的空间,空间复杂度为O(n^2);
5.心得体会(对本次实践收获及疑惑进行总结)
上机实践的时候还是做的比较慢,对动态规划的思想了解不透彻,做第一题的时候卡了很久,好在和同伴讨论过后完成了这道题,但是第三题课上就没时间做了,回来后参考了网上的解答再讨论了之后,又想了很久才写出来。这道题其实和最长公共子序列类似,我写代码时也参考了课本上的这最长公共子序列代码。动态规划,就是要将问题划分为子问题,将子问题的答案记录在表中。找到划分的方法确定子问题,理清思路,才能把这类问题解决好。