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

51 阅读3分钟

问题描述

小U和小R有两个字符串,分别是S和T。小U的目标是通过一系列操作将字符串S转换成字符串T的一个前缀。允许的操作有两种:修改S中的某一个字符,或者删除S末尾的字符。我们的任务是帮助小U计算出,最少需要多少次操作才能实现这个目标。

输入和输出

输入包含两个字符串S和T。输出是一个整数,表示最少需要的操作次数。

算法分析

这个问题可以通过动态规划或者贪心算法来解决。在这里,我们选择使用贪心算法,因为它的时间复杂度较低,且对于这个问题来说已经足够有效。

贪心算法的核心思想是,我们总是优先选择最长的公共前缀,然后对不匹配的部分进行操作。如果S和T在某一点之前是相同的,那么我们就不需要对这部分进行任何操作。一旦我们遇到了不匹配的字符,我们有两种选择:修改S中的字符或者删除S末尾的字符。由于修改一个字符的代价比删除一个字符的代价小,我们优先选择修改字符。

算法实现

算法的实现可以分为以下几个步骤:

  1. 比较S和T的公共前缀: 我们使用一个循环来比较S和T的公共前缀。只要S和T在当前位置的字符相同,我们就继续比较下一个字符。

  2. 计算不匹配字符的数量: 当S和T的字符不匹配时,我们计算出需要修改的字符数量。这个数量就是从当前位置到S的末尾的字符数量,因为这些字符都需要被修改。

  3. 处理S比T长的情况: 如果S的长度大于T的长度,那么超出的部分需要被删除。我们计算出S和T的长度差,并将其加到结果中。

  4. 返回结果: 最后,我们返回计算出的最小操作次数。

代码实现

以下是C++代码实现:

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

int solution(string S, string T) {
    int res = 0;
    int minLen = min(S.size(), T.size());
    for(int i = 0; i < minLen; i++) {
        if(S[i] != T[i])
            res++;
    }
    
    // 如果S比T长,那么超出的部分都需要被删除
    return S.size() > T.size() ? res + S.size() - T.size() : res;
}

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;
}

测试样例分析

  1. 样例1:S = "aba",T = "abb"。S和T的公共前缀是"ab",只需要修改S的最后一个字符'a'为'b',所以操作次数为1。
  2. 样例2:S = "abcd",T = "efg"。S和T没有公共前缀,所以需要对S进行4次修改,使其变成T的前缀。
  3. 样例3:S = "xyz",T = "xy"。S比T长,只需要删除S的最后一个字符'z',所以操作次数为1。
  4. 样例4:S = "hello",T = "helloworld"。S是T的前缀,不需要任何操作,所以操作次数为0。
  5. 样例5:S = "same",T = "same"。S和T相同,不需要任何操作,所以操作次数为0。

总结

通过贪心算法,我们可以有效地解决这个问题。算法的核心是优先选择最长的公共前缀,然后对不匹配的部分进行最小化操作。这种方法简单且高效,适用于处理字符串前缀问题。