📌  相关文章
📜  要替换 K 长度回文字符串的字符串连接的最少字符(1)

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

替换 K 长度回文字符串的字符串连接的最少字符

问题描述

给定一个长度为 $n$ 的字符串 $s$ 和一个整数 $k$,你需要进行若干次操作,将其中的每个长度为 $k$ 的回文子串替换为另一个字符串。你需要求出最小化操作次数的方案。

思路

首先我们考虑对于一个长度为 $k$ 的回文串,我们需要替换的最少字符数是多少?假设回文串为 $s_{i} s_{i+1} \cdots s_{i+k-1} $,其中 $s_{i} = s_{i+k-1}, \cdots s_{i+j} = s_{i+k-j-1}, \cdots, s_{i+\lfloor k/2 \rfloor} = s_{i+\lfloor k/2 \rfloor + 1}$。如果我们想要将回文串替换为另一个字符串 $t$,我们最少需要替换的字符数为 $\sum_{j=0}^{k-1} [s_{i+j} \neq t_{j}]$。

接下来我们考虑如何处理一次操作。我们假定当前字符串 $s$ 中长度为 $k$ 的回文串的集合为 $P$。 我们定义状态 $f(S)$,表示将 $S$ 中的所有回文串都替换成相同的字符串所需要的最少字符数。假设当前 $S$ 中有 $p$ 个不同的回文串,则有

$$ f(S) = \min_{1 \leq i \leq p} \left(f\big(S \backslash{ P_i }\big) + \sum_{j=0}^{k-1} [s_{i+j} \neq t_j ]\right) , $$

其中 $P_i$ 表示 $S$ 中第 $i$ 个回文串。

我们可以使用动态规划求解这个问题。状态转移方程为:

$$ f(S) = \begin{cases} 0, \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ S = \emptyset\ +\infty, \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ S \neq \emptyset \end{cases} $$

当 $S \neq \emptyset$ 时,我们考虑删除 $S$ 中的一个回文串,使得 $f(S)$ 取到最小值:

$$ f(S) = \min_{P_i \subseteq S} f\big(S \backslash{ P_i }\big) + \min_{t \in \Sigma^k} \sum_{j=0}^{k-1} [s_{i+j} \neq t_j ], $$

其中第二个式子是对所有可能的 $t$ 求最小值。

代码
def palindrome_min_replacement(s: str, k: int) -> int:
    n = len(s)
    f = {0: 0}
    pali_list = [s[i:i+k] for i in range(n-k+1) if s[i:i+k] == s[i+k-1:i-1:-1]]
    p = len(pali_list)

    for S in range(1, 2**(p+1)):   
        f[S] = float("inf")
        for i in range(p):
            if S & (1 << i):
                cost = sum(1 for j in range(k) if pali_list[i][j] != t[j])
                f[S] = min(f[S], f[S^(1<<i)] + cost)

    return f[2**p-1]

其中 $f[S]$ 表示将字符串 $s$ 中的回文子串集合 $S$ 替换为同一字符串所需替换的最少字符数。通过使用状态压缩的方式存储 $S$,我们可以快速实现这个动态规划。