📌  相关文章
📜  清空二进制字符串所需的连续相似字符的最小删除(1)

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

清空二进制字符串所需的连续相似字符的最小删除

本文将介绍如何计算清空一个二进制字符串所需的最小删除次数,以使得删除后的字符串中不含有任何连续相似字符。以字符串 "11000101101" 为例,我们需要删除两个相邻的1和两个相邻的0,得到的结果是 "10010101",不再含有连续相似字符。

方法一:贪心算法

我们可以从左到右扫描整个字符串,当遇到两个相邻的字符相同时,我们就将其中一个字符删除。在删除字符之后,我们需要判断删除该字符是否会使得前后两个字符变得相同。如果是,则我们需要继续删除相邻字符,直到不能再删除为止。这就是一个贪心的过程。

def min_deletion(s: str) -> int:
    i, n = 0, len(s)
    res = 0
    while i < n-1:
        if s[i] == s[i+1]:
            j = i+1
            while j < n and s[i] == s[j]:
                j += 1
            res += j-i-1
            i = j-1
        else:
            i += 1
    return res

复杂度分析:

时间复杂度:$O(n)$,其中 $n$ 是字符串的长度。

空间复杂度:$O(1)$,我们只需要常量级别的空间存储变量。

方法二:动态规划

我们可以使用动态规划的方法来解决此问题,设 $dp[i][0]$ 表示将字符 $s_i$ 替换成 0 时,使得前 $i+1$ 个字符没有相邻相同字符所需要删除的字符数量,$dp[i][1]$ 表示同理,将字符 $s_i$ 替换成 1 时所需的删除字符数量。

当 $s_{i-1} = 0$ 时,我们可以选择将 $s_i$ 替换为 1,也可以选择不替换,即 $dp[i][0] = \min(dp[i-1][0], dp[i-1][1]+1)$。当 $s_{i-1} = 1$ 时同理,$dp[i][1] = \min(dp[i-1][1], dp[i-1][0]+1)$。最后的答案是 $\min(dp[n-1][0],dp[n-1][1])$。

def min_deletion(s: str) -> int:
    n = len(s)
    dp = [[n, n] for _ in range(n)]
    dp[0][0] = s[0] == '1'
    dp[0][1] = s[0] == '0'
    for i in range(1, n):
        if s[i] == '0':
            dp[i][0] = min(dp[i-1][0], dp[i-1][1]+1)
            dp[i][1] = min(dp[i-1][1]+1, dp[i-1][0]+1)
        else:
            dp[i][1] = min(dp[i-1][1], dp[i-1][0]+1)
            dp[i][0] = min(dp[i-1][0]+1, dp[i-1][1]+1)
    return min(dp[n-1][0], dp[n-1][1])

复杂度分析:

时间复杂度:$O(n)$,其中 $n$ 是字符串的长度。

空间复杂度:$O(n)$,我们需要 $dp$ 数组存储状态。