题解:AcWing 899 编辑距离

【题目来源】

AcWing:899. 编辑距离 - AcWing题库

【题目描述】

给定 \(n\) 个长度不超过 \(10\) 的字符串以及 \(m\) 次询问,每次询问给出一个字符串和一个操作次数上限。

对于每次询问,请你求出给定的 \(n\) 个字符串中有多少个字符串可以在上限操作次数内经过操作变成询问给出的字符串。

每个对字符串进行的单个字符的插入、删除或替换算作一次操作。

【输入】

第一行包含两个整数 \(n\)\(m\)

接下来 \(n\) 行,每行包含一个字符串,表示给定的字符串。

再接下来 \(m\) 行,每行包含一个字符串和一个整数,表示一次询问。

字符串中只包含小写字母,且长度均不超过 \(10\)

【输出】

输出共 \(m\) 行,每行输出一个整数作为结果,表示一次询问中满足条件的字符串个数。

【输入样例】

3 2
abc
acd
bcd
ab 1
acbd 2

【输出样例】

1
3

【解题思路】

image

image

image

【算法标签】

《AcWing 899 编辑距离》 #动态规划# #线性DP#

【代码详解】

// 引入所有标准库头文件,方便使用各种标准库功能
#include <bits/stdc++.h>

// 使用标准命名空间,避免每次使用标准库函数时都需要加 std:: 前缀
using namespace std;

// 定义常量
const int N = 1005;  // 定义数组的最大尺寸为1005,以适应字符串长度的需求

// 定义全局变量
int n, m;            // n: 字符串的数量,m: 询问的次数
char str[N][N];      // str[N][N]: 存储输入的n个字符串,每个字符串的字符下标从1开始存放
int f[15][15];       // f[i][j]: 表示将字符串a的前i个字符转换成字符串b的前j个字符所需的最小操作数

// 函数声明:计算将字符串a转换成字符串b的编辑距离
int edit_dis(char a[], char b[]);  // 求a[]变换到b[]的编辑距离

// 主函数,程序的入口点
int main()
{
    // 读取字符串的数量n和询问的次数m
    cin >> n >> m;

    // 循环读取n个字符串,每个字符串的字符下标从1开始存放
    for (int i = 0; i < n; i++)  
        cin >> str[i] + 1;

    // 处理m次询问
    while (m--) 
    {
        // 定义临时字符数组s,用于存储询问的目标字符串,字符下标从1开始存放
        char s[15];  
        // 定义变量lim,表示允许的最大编辑距离
        int lim;
        // 读取询问的目标字符串s和允许的最大编辑距离lim,字符下标从1开始存放
        cin >> s + 1 >> lim;

        // 初始化结果变量res,用于统计满足编辑距离限制的字符串个数
        int res = 0;  

        // 遍历所有n个字符串,统计编辑距离不超过lim的字符串数量
        for (int i = 0; i < n; i++)  
            // 如果字符串str[i]转换成字符串s的编辑距离小于等于lim,则计数加1
            if (edit_dis(str[i], s) <= lim) 
                res++;

        // 输出满足条件的字符串个数
        cout << res << endl;
    }

    // 程序正常结束,返回0
    return 0;
}

// 函数定义:计算将字符串a转换成字符串b的编辑距离
int edit_dis(char a[], char b[])  // 求a[]变换到b[]的编辑距离
{
    // 计算字符串a和字符串b的长度,字符下标从1开始存放
    int la = strlen(a + 1), lb = strlen(b + 1);  // a、b存放起始地址是1,不是0

    // 初始化动态规划数组f的第一行,表示将0个a字符转换成b的前i个字符所需的操作数
    for (int i = 0; i <= lb; i++)  
        f[0][i] = i;  // 表示0个a数组字符变到b数组i个字符步骤

    // 初始化动态规划数组f的第一列,表示将a的前i个字符转换成0个b字符所需的操作数
    for (int i = 0; i <= la; i++)  
        f[i][0] = i;  // 表示i个a数组字符变到b数组0个字符步骤

    // 动态规划计算将字符串a的前i个字符转换成字符串b的前j个字符所需的最小操作数
    for (int i = 1; i <= la; i++)  
        for (int j = 1; j <= lb; j++) 
        {
            // 如果当前字符a[i]和b[j]相等,则不需要进行操作,直接继承前一个状态
            if (a[i] == b[j]) 
                f[i][j] = f[i - 1][j - 1];  // 不需要操作
            else 
            {
                // 如果当前字符a[i]和b[j]不相等,则需要进行以下三种操作中的一种,并选择最小操作数
                // 1. 删除a[i]: f[i-1][j] + 1
                // 2. 在a[i]后插入b[j]: f[i][j-1] + 1
                // 3. 替换a[i]为b[j]: f[i-1][j-1] + 1
                f[i][j] = min(min(f[i - 1][j], f[i][j - 1]), f[i - 1][j - 1]) + 1;
            }
        }

    // 返回将字符串a转换成字符串b所需的最小编辑操作数
    return f[la][lb];
}

【运行结果】

3 2
abc
acd
bcd
ab 1
1
acbd 2
3
posted @ 2026-02-25 08:04  团爸讲算法  阅读(0)  评论(0)    收藏  举报