📌  相关文章
📜  获得给定字符串所需的从头到尾的X或Y字符追加的最小数量(1)

📅  最后修改于: 2023-12-03 15:27:52.143000             🧑  作者: Mango

字符串追加问题

问题描述

给定一个字符串s,只包含字符X和Y。现在需要求出在s字符串的末尾添加字符X或Y,使得最终字符串满足从头到尾的字符是严格递增的,即不会出现 XXY 或 YYX 这样的情况。

请编写一个函数接受一个字符串s作为参数,返回添加字符的最小数量。

如示例:输入 s = "YXYXXXY",输出2,因为在结尾添加两个X,即"YXYXXXYXX",则从头到尾的字符严格递增。

解法思路
贪心算法

由于只允许在字符串末尾添加字符,所以可以使用贪心算法求解。

从前往后扫描字符串s,记录当前需要添加的字符类型(即X或Y)和该类型字符的数量,如果下一个字符比当前字符小,则需要在结尾添加一个与当前字符不同的字符。此时根据贪心思想,应该尽可能添加当前类型字符的反向类型,即如果当前字符为X,则应该在结尾添加Y;如果当前字符为Y,则应该在结尾添加X。同时,更新当前需要添加的字符类型和数量,直到扫描完整个字符串。

由于仅需记录字符类型和数量,时间复杂度为O(n),是一种快速且简单的解法。

动态规划算法

另一种经典的算法是动态规划,使用一个二维数组dp表示将s字符串前i个字符转换成字符递增需要添加的最小字符数。其中,dp[i][0]表示在s[i-1]位置添加X的最小字符数,dp[i][1]表示在s[i-1]位置添加Y的最小字符数。

对于每个字符s[i-1],可以判断它是否比前一个字符s[i-2]小,如果小,则需要添加一个不同的类型字符。则有:

  • 若s[i-1]为X,则在s[i-1]位置添加Y,即dp[i][1] = dp[i-1][0]+1,dp[i][0] = dp[i-1][0];
  • 若s[i-1]为Y,则在s[i-1]位置添加X,即dp[i][0] = dp[i-1][1]+1,dp[i][1] = dp[i-1][1]。

最终的结果就是dp[n][0]和dp[n][1]的较小值,其中n为字符串s的长度。

这种方法的时间复杂度为O(n),需要一个二维数组存储中间结果,空间复杂度为O(n)。

代码实现
贪心算法
def append_string(s: str) -> int:
    if not s:
        return 0
    cnt, pre = 0, ''
    for i in range(len(s)):
        if pre and s[i] < pre:
            cnt += 1
            pre = 'Y' if pre == 'X' else 'X'
        pre_cnt = s[:i+1].count(pre)
        oppo_cnt = i+1-pre_cnt
        if pre_cnt <= oppo_cnt:
            pre = 'X'
        else:
            pre = 'Y'
    return cnt
动态规划算法
def append_string(s: str) -> int:
    if not s:
        return 0
    dp = [[0, 0] for _ in range(len(s)+1)]
    for i in range(1, len(s)+1):
        if s[i-1] < s[i-2]:
            dp[i][0] = dp[i-1][1]+1
            dp[i][1] = dp[i-1][1]
        else:
            dp[i][0] = dp[i-1][0]
            dp[i][1] = dp[i-1][0]+1
    return min(dp[-1])