动态规划-字符串的比较问题

1.问题描述

2.问题分析

      在给定两个字符串A和B,我们需要通过在字符串A中插入空格来使得A和B的长度相同,并且使得它们的“扩展距离”最小。扩展距离是指在相同位置上字符ASCII码差的绝对值之和,空格字符与其他字符的距离为k。我们需要利用动态规划算法将这个复杂问题分解成更小的子问题,自底向上的计算各个子问题并利用每次计算的结果,避免重复运算。对于这个问题我们可以定义一个二维数组dp[i][j],其中dp[i][j]表示字符串A的前i个字符和字符串 B的前j个字符的最小扩展距离。

3.解题思路

1.初始化动态规划数组,dp[0][0] 显然为 0,因为两个空字符串的扩展距离为 0。

2.对于 dp[i][0],即字符串 B 为空的情况,字符串 A 的扩展距离就是将 A 中的每个字符都与空格进行比较的距离之和。

3.对于 dp[0][j],即字符串 A 为空的情况,字符串 B 的扩展距离就是将 B 中的每个字符都与空格进行比较的距离之和。

4.对于其他情况,我们需要考虑三种情况: 字符 A[i] 与字符 B[j] 匹配,那么 dp[i][j] = dp[i-1][j-1] + dist(A[i], B[j])。 字符 A[i] 与空格匹配,那么 dp[i][j] = dp[i-1][j] + k。 字符 B[j] 与空格匹配,那么 dp[i][j] = dp[i][j-1] + k。

5.我们需要取上述三种情况的最小值作为 dp[i][j] 的值,即dp[i][j]=min{ dp[i-1][j] + k + k,dp[i][j-1] + k,dp[i-1][j-1] + dist(A[i], B[j])}

6.最后,dp[len(A)][len(B)] 就是我们要找的答案。题中字符串A的长度为3,B为4。

4.算法原理

初始化第一行和第一列

dp[0][0] = 0 (两个空字符串的扩展距离为 0)

dp[1][0] = 2 (A的第一个字符 'c' 与空格的距离)

dp[2][0] = 4 (A的前两个字符 "cm" 与空格的距离)

dp[3][0] = 6 (A的前三个字符 "cmc" 与空格的距离)

dp[0][1] = 2 (B的第一个字符 's' 与空格的距离)

dp[0][2] = 4 (B的前两个字符 "sn" 与空格的距离)

dp[0][3] = 6 (B的前三个字符 "snm" 与空格的距离)

dp[0][4] = 8 (B的前四个字符 "snmn" 与空格的距离

dp值递推计算公式

dp[i][j]=min{dp[i-1][j] + k + k,dp[i][j-1] + k,

dp[i-1][j-1] + dist(A[i], B[j])}

dp值计算示例

dp[1][1] = min(dp[0][0] + |'c' - 's'|, dp[1][0] + k, dp[0][1] + k)        

= min(0 + 8, 2 + 2, 2 + 2)          

= min(8, 4, 4)  、

= 4

以此类推dp[3][4] = 10(最终,cmc与snmn的最小扩展距离为10)

5.代码实现

完整代码

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;

int calculateDistance(char a, char b, int k) {
    if (a == ' ' || b == ' ') return k;
    return abs(a - b);
}

int main() {
    ifstream fin("C:\\Users\\xiaofanzi\\Desktop\\suanfawork\\input.txt");
    ofstream fout("C:\\Users\\xiaofanzi\\Desktop\\suanfawork\\output.txt");
    string A, B;
    int k;
    fin >> A >> B >> k;

    int m = A.length(), n = B.length();
    vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));

    // 初始化
    for (int i = 1; i <= m; ++i) dp[i][0] = i * k;
    for (int j = 1; j <= n; ++j) dp[0][j] = j * k;

    // 动态规划填表
    for (int i = 1; i <= m; ++i) {
        for (int j = 1; j <= n; ++j) {
            int cost = calculateDistance(A[i - 1], B[j - 1], k);
            dp[i][j] = min({ dp[i - 1][j - 1] + cost, dp[i][j - 1] + k, dp[i - 1][j] + k });
        }
    }

    // 打印dp表
    for (int i = 0; i <= m; ++i) {
        for (int j = 0; j <= n; ++j) {
            cout << dp[i][j] << " ";
        }
        cout << endl;
    }
    fout << dp[m][n] << endl;

    fin.close();
    fout.close();
    return 0;

结果展示

 

  • 19
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于动态规划解决字符串修改问题,我可以给你一些解释。动态规划是一种常见的算法思想,用于解决具有重叠子问题和最优子结构性质的问题字符串修改问题可以看作是一种编辑距离问题,也就是将一个字符串转换成另一个字符串所需的最少操作数,包括插入、删除、替换等操作。动态规划的思想是将问题分解成子问题,通过求解子问题的最优解来得到原问题的最优解。 具体来说,我们可以定义一个二维数组dp[i][j],表示将字符串s1的前i个字符转换成字符串s2的前j个字符所需的最少操作数。其中,dp[0][0]=0,表示两个空字符串之间的编辑距离为0。对于dp[i][j],我们可以分三种情况讨论: 1. s1的第i个字符和s2的第j个字符相同,此时不需要进行任何操作,dp[i][j]=dp[i-1][j-1]。 2. s1的第i个字符和s2的第j个字符不同,此时我们需要进行插入、删除或替换操作,那么dp[i][j]就可以由以下三种情况转移得到: - 插入操作:在s1的第i个字符后面插入s2的第j个字符,即dp[i][j]=dp[i][j-1]+1。 - 删除操作:将s1的第i个字符删除,即dp[i][j]=dp[i-1][j]+1。 - 替换操作:将s1的第i个字符替换成s2的第j个字符,即dp[i][j]=dp[i-1][j-1]+1。 3. 当i=0或j=0时,其中一个字符串为空字符串,此时dp[i][j]的值就等于另一个字符串的长度。 最后,dp[n][m]就是将字符串s1转换成字符串s2所需的最小操作数,其中n和m分别表示字符串s1和s2的长度。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值