📌  相关文章
📜  在给定的约束下,从字符串删除最少的字符以将其分成三个子字符串(1)

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

从字符串删除最少的字符以将其分成三个子字符串

问题描述

给定一个字符串,需要将其分成三个子字符串。要求分割后的子字符串长度分别为 $a, b, c$,且 $a \leq b \leq c$。请你在满足上述条件的前提下,删除尽可能少的字符,使得原字符串可以被分成三个满足要求的子字符串。

解决方案
思路

对于字符串 $s$,我们可以从左到右遍历字符串,设当前处理的位置为 $i$,我们枚举第二个子字符串的结束位置 $j$ 和第三个子字符串的结束位置 $k$,我们需要满足下面的两个条件:

  • 第一个子字符串的长度为 $i$;
  • 第二个子字符串的长度为 $j - i$;
  • 第三个子字符串的长度为 $k - j$;
  • 最后一个子字符串须覆盖整个字符串。

设 $s1$ 为前 $i$ 个字符组成的子串,$s2$ 为第 $i+1$ 到 $j$ 个字符组成的子串,$s3$ 为第 $j+1$ 到 $k$ 个字符组成的子串,$s4$ 为第 $k+1$ 到 $n$ 个字符组成的子串,可以得到下面这个等式:

$$a + b + c + d = n,\quad i < j < k$$

要使得删除的字符最少,我们需要尽可能地让第二个子字符串和第三个子字符串的长度尽可能地大,即 $b$ 和 $c$ 距离 $i$ 和 $j$ 的位置尽量远。

为了使得复杂度为 $O(n)$,我们可以先遍历一遍字符串,计算出 $i$ 和 $j$ 的所有情况下可能的最大值和最小值,然后对于每个 $i$ 和 $j$,计算出 $k$ 以及对应的 $c$ 和 $d$,最终取删除的字符数最少的方案。

代码

我们先计算出 $i$ 和 $j$ 的上下界,然后枚举每个 $i$ 和 $j$,计算出 $k$ 和对应的 $c$ 和 $d$。时间复杂度为 $O(n)$。

def solve(s):
    n = len(s)
    INF = float("inf")

    # 预处理出 i 和 j 的上下界
    mi_j = [n]*n
    mx_i, mi_i = -1, INF
    for i in range(n):
        if i > mx_i: mx_i = i
        if s[i] < s[mx_i]: mx_i = i
        if i < mi_i: mi_i = i
        if mx_i - i > mi_j[mx_i]: mi_j[mx_i] = mx_i - i
        if i - mi_i > mi_j[mx_i]: mi_j[mx_i] = i - mi_i

    mx_j, mi_j = -1, INF
    for j in range(n):
        if j > mx_j: mx_j = j
        if s[j] < s[mx_j]: mx_j = j
        if j < mi_j: mi_j = j
        if mx_j - j > mi_j: mi_j = mx_j - j
        if j - mi_j > mi_j: mi_j = j - mi_j

    ans = INF
    for i in range(n):
        for j in range(i + 1, n):
            if j - i > mi_j[j]: continue
            if n - j > mi_j[n - 1]: continue
            k = j + 1
            while k < n and s[k] <= s[i] and (k - j <= mi_j[j]) and (n - k <= mi_j[n - 1]):
                k += 1
            if k == n: continue
            ans = min(ans, n - (k + 1))
    return ans
总结

本问题可以通过预处理出 $i$ 和 $j$ 的上下界,并枚举每个 $i$ 和 $j$,计算出 $k$ 和对应的 $c$ 和 $d$ 来解决。复杂度为 $O(n)$。