每日算法:最少前缀操作问题

127 阅读3分钟

最少前缀操作问题解析

问题描述

给定两个字符串 S 和 T,目标是通过一系列操作将 S 转变为 T 的前缀。操作包括两种类型:

  1. 修改操作:可以更改 S 中的任意字符,使其与 T 中相应位置的字符相匹配。
  2. 删除操作:可以移除 S 末尾的字符,直到其长度不超过 T。

我们的目标是计算出将 S 转换为 T 的前缀所需的最少操作次数。

思路分析

1. 前缀匹配的理解

前缀是指一个字符串的起始部分。例如,"abc" 的前缀包括:""、"a"、"ab" 和 "abc"。任务是将 S 转变为 T 的前缀,即保留 S 的一部分,使其与 T 相匹配,并处理多余的部分。

2. 确定最大公共前缀

首先,我们需要确定 S 和 T 的最大公共前缀,即两者从左到右相同的部分。不属于这个公共前缀的部分需要通过操作来处理。

3. 操作细节

  • 修改操作:当 S 和 T 的最大公共前缀不一致时,需要更改 S 中的某些字符以匹配 T。
  • 删除操作:如果 S 的长度超过 T,需要移除 S 末尾的字符,以使其成为 T 的前缀。

4. 优化策略

为了找到最少的操作次数,我们可以分两步计算:

  • 计算最大公共前缀的长度。
  • 对于超出公共前缀的部分,分别计算修改和删除操作的次数。

解题步骤

  1. 计算最大公共前缀长度:从 S 和 T 的开头开始比较,直到遇到第一个不同的字符或任一字符串结束。
  2. 修改操作:对于不匹配的字符,每次操作可以更改 S 中的字符,以匹配 T 中的字符。
  3. 删除操作:如果 S 的长度超过 T,则需要移除 S 中的多余字符。
  4. 返回操作次数:将修改和删除操作的次数相加,得到总的最少操作次数。

代码实现

def min_operations(S: str, T: str) -> int:
    # 计算 S 和 T 的最大公共前缀长度
    common_prefix_len = 0
    while common_prefix_len < len(S) and common_prefix_len < len(T) and S[common_prefix_len] == T[common_prefix_len]:
        common_prefix_len += 1
    
    # 计算 S 中与 T 不匹配的字符数量
    modify_count = sum(1 for i in range(common_prefix_len, len(T)) if S[i] != T[i])
    
    # 计算需要删除的 S 的末尾字符数量
    delete_count = len(S) - common_prefix_len
    
    # 返回总的操作次数
    return modify_count + delete_count

# 测试用例
if __name__ == '__main__':
    print(min_operations("aba", "abb"))  # 输出:1
    print(min_operations("abcd", "efg"))  # 输出:4
    print(min_operations("xyz", "xy"))  # 输出:1
    print(min_operations("hello", "helloworld"))  # 输出:0
    print(min_operations("same", "same"))  # 输出:0

复杂度分析

  • 时间复杂度:O(min(len(S), len(T))),因为我们需要遍历 S 和 T 的前缀部分进行比较。
  • 空间复杂度:O(1),因为我们只使用了常数级别的额外空间。