题目解析:最少前缀操作问题 | 豆包MarsCode AI 刷题

95 阅读5分钟

问题描述

小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 进行特定操作(修改某一个字符或者删除 S 末尾的字符),使得 S 变成字符串 T 的一个前缀,并且要计算出最少的操作次数。整体思路可以拆分为以下几个步骤来实现:

  1. 处理字符串长度差异(确定删除字符数量)
    首先比较 S 和 T 的长度。如果 S 的长度大于 T 的长度,那么就需要删除 S 末尾多余的字符,使其长度不超过 T 的长度,多余的字符数量就是需要删除的字符数量;若 S 的长度小于等于 T 的长度,则不需要进行删除操作,删除字符数量为 0。
  2. 截断字符串 S (便于后续比较)
    根据上述长度比较的结果,对 S 进行截断操作。当 S 长度大于 T 长度时,通过切片取 S 的前 len_T 个字符(即 S[:len_T] ),得到一个新的字符串 S_new,其长度与 T 长度匹配或者小于 T 长度(当 S 原本长度就不超过 T 时,S_new 就是原 S ),这样后续可以逐位与 T 进行比较来确定修改字符的数量。
  3. 计算修改字符的数量
    对得到的 S_new 和 T 从第一个字符开始,按位进行比较(通过循环遍历 S_new 的每个字符位置)。当对应位置的字符不相同时,意味着需要进行一次修改操作,将修改字符的计数器加 1,遍历完 S_new 后就能得到总共需要修改的字符数量。
  4. 计算总操作次数并返回结果
    最后,把前面计算得到的删除字符数量和修改字符数量相加,得到的总和就是将 S 变为 T 的一个前缀所需要的最少操作次数,将这个结果返回即可。

实现过程分析

1. 变量定义部分

len_S = len(S)
len_T = len(T)

通过 len() 函数分别获取输入字符串 S 和 T 的长度,并将其存储在变量 len_S 和 len_T 中。这样做方便后续基于长度进行各种判断和计算,避免了多次重复调用 len() 函数。

2. 计算删除字符数量部分

deletions = max(0, len_S - len_T)

这行代码通过取 len_S - len_T 和 0 的最大值来确定需要删除的字符数量。逻辑是:如果 len_S 大于 len_T,那么 len_S - len_T 的差值就是要删除的 S 末尾多余的字符数;而如果 len_S 小于等于 len_T,则 len_S - len_T 为非正数,此时不需要删除字符,按照 max() 函数的作用,就会返回 0,符合题目要求的删除字符数量逻辑。

3. 截断字符串 S 部分

S_new = S[:len_T] if len_S > len_T else S

根据 S 和 T 的长度关系对 S 进行处理。使用了 Python 的条件表达式(三元表达式),当 len_S 大于 len_T 时,通过切片操作 S[:len_T] 截断 S,使其长度变为和 T 一样长;如果 len_S 小于等于 len_T,则直接使用原 S 作为 S_new,确保后续比较修改操作时两个字符串长度匹配或者 S 的长度处于合理范围,方便下一步进行逐字符比较。

4. 计算修改字符数量部分

modifications = 0
for i in range(len(S_new)):
    if S_new[i]!= T[i]:
        modifications += 1

首先初始化修改字符数量的计数器 modifications 为 0。然后利用 for 循环遍历处理后的字符串 S_new(其长度要么等于 T 的长度,要么小于等于 T 的长度),在循环内通过条件判断 if S_new[i]!= T[i]: 来比较对应位置的字符是否相同,如果不同则意味着此处需要进行一次修改操作,将 modifications 的值加 1,以此统计出将 S_new 变为 T 的对应前缀部分需要修改的字符个数。

5. 计算总操作次数并返回部分

total_operations = deletions + modifications
return total_operations

将前面分别计算得到的删除字符的操作次数 deletions 和修改字符的操作次数 modifications 相加,得到总的操作次数 total_operations,最后通过 return 语句将这个总操作次数返回,完成函数功能,使得调用该函数时能获取到将 S 变为 T 的一个前缀所需要的最少操作次数。

完整代码

def solution(S: str, T: str) -> int:
    len_S = len(S)
    len_T = len(T)
    
    # 计算需要删除的字符数量
    deletions = max(0, len_S - len_T)
    
    # 截断 S,使其长度不超过 T
    S_new = S[:len_T] if len_S > len_T else S
    
    # 计算需要修改的字符数量
    modifications = 0
    for i in range(len(S_new)):
        if S_new[i] != T[i]:
            modifications += 1
    
    # 总操作次数
    total_operations = deletions + modifications
    return total_operations
 
if __name__ == '__main__':
    print(solution("aba", "abb") == 1)        
    print(solution("abcd", "efg") == 4)       
    print(solution("xyz", "xy") == 1)           
    print(solution("hello", "helloworld") == 0)
    print(solution("same", "same") == 0)        

复杂度分析

该算法的时间复杂度主要由两个部分构成:首先,计算公共前缀的长度需要遍历 ST 中的字符,最坏情况下,最多需要遍历 min(len(S), len(T)) 个字符,因此该部分的时间复杂度是 O(min(len(S), len(T)))。其次,比较公共前缀部分的字符是否匹配也需要遍历最短字符串的前缀部分,这一部分的时间复杂度同样是 O(min(len(S), len(T)))。因此,整个算法的时间复杂度为 O(min(len(S), len(T)))。在空间复杂度方面,只使用了常数级别的额外空间,因此空间复杂度为 O(1)。