青训营-最少前缀操作问题

237 阅读3分钟

问题描述

小U和小R有两个字符串,分别是SS和TT,现在小U需要通过对SS进行若干次操作,使其变成TT的一个前缀。操作可以是修改SS的某一个字符,或者删除SS末尾的字符。现在你需要帮助小U计算出,最少需要多少次操作才能让SS变成TT的前缀。


测试样例

样例1:

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

样例2:

输入:S = "abcd", T = "efg"
输出:4

样例3:

输入:S = "xyz", T = "xy"
输出:1

样例4:

输入:S = "hello", T = "helloworld"
输出:0

样例5:

输入:S = "same", T = "same"
输出:0

问题分析

我们需要将字符串 S 通过一系列操作(删除末尾字符或修改字符)转换成字符串 T 的前缀。这里的“前缀”是指 T 的一部分,即 T 的一个子串,该子串位于 T 的起始位置。

解题思路

  1. 找到最长公共前缀

    • 首先,我们需要找到 S 和 T 的最长公共前缀。这可以通过逐字符比较 S 和 T 来完成,直到遇到第一个不相等的字符为止。
  2. 处理 ST 的差异

    • 如果 S 的长度小于或等于 T 的长度:

      • 我们只需要关注从最长公共前缀之后开始的不同字符。对于每一个不同的字符,我们都需要执行一次修改操作。
    • 如果 S 的长度大于 T 的长度:

      • 除了需要处理从最长公共前缀之后开始的不同字符外,我们还需要删除 S 中超过 T 长度的那些字符。

JAVA代码1(不能处理样例8)

public class Main{
public static int solution(String S, String T) {
    int operations = 0;

    // 找到最长公共前缀长度
    int commonPrefixLength = 0;
    int minLength = Math.min(S.length(), T.length());
    for (int i = 0; i < minLength; i++) {
        if (S.charAt(i) != T.charAt(i)) {
            break;
        }
        commonPrefixLength++;
    }

    // 如果 S 的长度小于或等于 T 的长度
    if (S.length() <= T.length()) {
        // 计算需要修改的字符数
        int modifyCount = 0;
        for (int i = commonPrefixLength; i < minLength; i++) {
            if (S.charAt(i) != T.charAt(i)) {
                modifyCount++;
            }
        }
        operations = modifyCount;
    } else {
        // 如果 S 的长度大于 T 的长度
        // 计算需要修改的字符数
        int modifyCount = 0;
        for (int i = commonPrefixLength; i < minLength; i++) {
            if (S.charAt(i) != T.charAt(i)) {
                modifyCount++;
            }
        }
        // 计算需要删除的字符数
        int deleteCount = S.length() - commonPrefixLength - modifyCount;
        operations = modifyCount + deleteCount;
    }

    return operations;
}

public static void main(String[] args) {
    System.out.println(solution("aba", "abb")); // 输出:1
    System.out.println(solution("abcd", "efg")); // 输出:4
    System.out.println(solution("xyz", "xy")); // 输出:1
    System.out.println(solution("hello", "helloworld")); // 输出:0
    System.out.println(solution("same", "same")); // 输出:0
    System.out.println(solution("bbbabaaaaa", "baaabaaabaaaba")); // 预期输出:3
}
}

image.png

改进思路

  1. 简化删除计数逻辑: 在处理 S 长度大于 T 的情况时,您计算需要删除的字符数的方式是从最长公共前缀之后开始计算不同字符的数量,然后再减去公共前缀的长度。实际上,我们只需要计算 S 中超过 T 长度的那部分字符数量即可。
  2. 优化计算方式: 我们直接用 S.length() - T.length() 来计算 S 需要删除的字符数。这是因为超过 T 长度的那部分 S 必须被删除,而不用再去逐字符对比。

正确Java代码

public class Main {
public static int solution(String S, String T) {
    int operations = 0;

    // 找到最长公共前缀长度
    int commonPrefixLength = 0;
    int minLength = Math.min(S.length(), T.length());
    for (int i = 0; i < minLength; i++) {
        if (S.charAt(i) != T.charAt(i)) {
            break;
        }
        commonPrefixLength++;
    }

    // 如果 S 的长度小于或等于 T 的长度
    if (S.length() <= T.length()) {
        // 计算需要修改的字符数
        int modifyCount = 0;
        for (int i = commonPrefixLength; i < minLength; i++) {
            if (S.charAt(i) != T.charAt(i)) {
                modifyCount++;
            }
        }
        operations = modifyCount;
    } else {
        // 如果 S 的长度大于 T 的长度
        // 计算需要修改的字符数
        int modifyCount = 0;
        for (int i = commonPrefixLength; i < minLength; i++) {
            if (S.charAt(i) != T.charAt(i)) {
                modifyCount++;
            }
        }
        // 计算需要删除的字符数
        int deleteCount = S.length() - T.length(); // 直接计算 S 需要删除的字符数
        operations = modifyCount + deleteCount;
    }

    return operations;
}

public static void main(String[] args) {
    System.out.println(solution("aba", "abb")); // 输出:1
    System.out.println(solution("abcd", "efg")); // 输出:4
    System.out.println(solution("xyz", "xy")); // 输出:1
    System.out.println(solution("hello", "helloworld")); // 输出:0
    System.out.println(solution("same", "same")); // 输出:0
    System.out.println(solution("bbbabaaaaa", "baaabaaabaaaba")); // 预期输出:3
}
}