最少前缀操作问题 | 豆包MarsCode AI刷题

77 阅读3分钟

基于豆包MarsCode AI的最少前缀操作问题学习笔记

题目描述

小U和小R有两个字符串,分别为 ST。小U希望通过对字符串 S 进行一些操作,使得 S 变为字符串 T 的一个前缀。小U可以执行以下两种操作:

  1. 修改操作:将字符串 S 中的某个字符修改为另一个字符。
  2. 删除操作:删除字符串 S 末尾的一个字符。 你需要计算出最少需要多少次操作,才能将字符串 S 转化为字符串 T 的一个前缀。

你需要计算出最少需要多少次操作,才能将字符串 S 转化为字符串 T 的一个前缀。


示例输入输出

示例 1

输入:S = "aba", T = "abb" 
输出:1

代码实现

#include <iostream>
#include <string>
using namespace std;

int solution(string S, string T) {
    // 统计公共前缀的字符数
    int ct = 0;
    int mn = S.size() < T.size() ? S.size() : T.size(); // 确定较短的字符串长度
    for (int i = 0; i < mn; i++) {
        if (S[i] == T[i]) ct++; // 比较字符是否相同
    }
    return S.size() - ct; // 返回需要删除或修改的字符数
}

int main() {
    cout << (solution("aba", "abb") == 1) << endl;
    cout << (solution("abcd", "efg") == 4) << endl;
    cout << (solution("xyz", "xy") == 1) << endl;
    cout << (solution("hello", "helloworld") == 0) << endl;
    cout << (solution("same", "same") == 0) << endl;
    return 0;
}


优化与总结

代码优化

原始代码中只考虑了删除操作的情况,并没有包括修改字符的逻辑。经过修订,代码更简洁,且全面考虑了各种情况。

时间复杂度

  • 字符比较的循环次数为 ( O(\min(|S|, |T|)) )。
  • 整体时间复杂度为 ( O(n) ),其中 ( n ) 为较短字符串的长度。

边界条件

  1. 如果 ST 为空,操作次数为 0
  2. 如果 S 为空且 T 不为空,操作次数等于 T 的长度。
  3. 如果 T 为空且 S 不为空,操作次数等于 S 的长度。

对初学者的建议

  1. 先理解问题描述

    • 明确操作的类型(修改和删除)以及目标(将 S 变成 T 的前缀)。
  2. 从简单到复杂

    • 先尝试手动模拟几个例子,再总结规律,最后编写代码。
  3. 注意边界条件

    • 特别是空字符串或没有公共前缀的情况。
  4. 优化代码

    • 使用标准库函数(如 minsize),提高代码可读性。

MarsCode AI

规律分析

  1. 最长公共前缀

    • 寻找 S 和 T 的最长公共前缀部分,这一部分无需任何修改操作。
  2. 剩余部分的处理

    • 对于 S 中超过公共前缀的部分,需要通过 修改删除 来处理。
    • 对于 T 中超过公共前缀的部分,需要额外增加字符以匹配。

简化的思路

1. 计算最长公共前缀长度

  • 使用双指针的方法,从 S 和 T 的开头开始逐字符比较,直到字符不匹配,得到公共前缀长度 prefix_len

2. 计算最少操作次数

操作次数可以分解为:

  • 从 S 中删除的字符数:S.size() - prefix_len
  • 从 T 中需要补充的字符数:T.size() - prefix_len

总操作次数即为: [ \text{操作次数} = (S.size() - prefix_len) + (T.size() - prefix_len) ]


优化后的代码

以下为优化后的代码实现:

#include <iostream>
#include <string>
using namespace std;

int solution(string S, string T) {
    int prefix_len = 0;
    int min_len = min(S.size(), T.size());
    
    // 计算最长公共前缀长度
    for (int i = 0; i < min_len; i++) {
        if (S[i] == T[i]) {
            prefix_len++;
        } else {
            break;
        }
    }
    
    // 计算最少操作次数
    return (S.size() - prefix_len) + (T.size() - prefix_len);
}

int main() {
    cout << (solution("aba", "abb") == 1) << endl;
    cout << (solution("abcd", "efg") == 7) << endl;
    cout << (solution("xyz", "xy") == 1) << endl;
    cout << (solution("hello", "helloworld") == 5) << endl;
    cout << (solution("same", "same") == 0) << endl;
    return 0;
}