加载中...

前后缀分解

题目

给你两个字符串 s 和 t 。

你可以从字符串 t 中删除任意数目的字符。

如果没有从字符串 t 中删除字符,那么得分为 0 ,否则:

令 left 为删除字符中的最小下标。
令 right 为删除字符中的最大下标。
字符串的得分为 right - left + 1 。

请你返回使 t 成为 s 子序列的最小得分。

一个字符串的 子序列 是从原字符串中删除一些字符后(也可以一个也不删除),剩余字符不改变顺序得到的字符串。(比方说 "ace" 是 "abcde" 的子序列,但是 "aec" 不是)。

示例

示例1:
输入:s = "abacaba", t = "bzaa"
输出:1
解释:这个例子中,我们删除下标 1 处的字符 "z" (下标从 0 开始)。
字符串 t 变为 "baa" ,它是字符串 "abacaba" 的子序列,得分为 1 - 1 + 1 = 1 。
1 是能得到的最小得分。

示例2:
输入:s = "cde", t = "xyz"
输出:3
解释:这个例子中,我们将下标为 0, 1 和 2 处的字符 "x" ,"y" 和 "z" 删除(下标从 0 开始)。
字符串变成 "" ,它是字符串 "cde" 的子序列,得分为 2 - 0 + 1 = 3 。
3 是能得到的最小得分。

策略

考察的知识点:字符串前后缀分解

[参考了灵神讲解]

  1. 注意到得分指的是 删除字符中的最大下标 right - 删除字符中的最小下标left + 1, 那么在[left,right],我们删除一部分和删除全部得到的分数是一样的,那么贪心的去想,删的越多(剩的越少)就越可能成为子序列,那么就索性直接删除一个子字符串,问题就变成了从t中删除一个子字符串,使剩余的部分成为s的一个子序列

  2. 怎么找要删除的子串?
    答:将s分割成两个部分,分别去匹配t的前缀和后缀,找匹配长度之和最大的一个方案

Code

C++ version

class Solution {
public:
    int minimumScore(string s, string t) {
        // 前后缀分解
        int n = s.length(), m = t.length();
        int suf[n + 1]; // # suf[i] = j 表示匹配后缀s[i:] 匹配了 t[j:]
        // 为什么多开一个因为后面用到了suf[n]
        // suf[n] = m, 表示i不拿字符出来,t也匹配不出
        suf[n] = m;
        // 倒叙枚举分割位置,求后缀匹配
        for (int i = n - 1, j = m - 1; i >= 0; i--) {
            if (j >= 0 && s[i] == t[j]) j--;
            suf[i] = j + 1;
        }
        // 表示通过后缀匹配 去掉t[:suf[0]]
        int res =  suf[0];
        // 正序枚举分割位置,求前缀匹配,并更新答案
        for (int i = 0, j= 0; i < n; i++) {
            if (j < m && s[i] == t[j]) {
                j++;
                if (suf[i + 1] - j >= 0) 
                    res = min(res, suf[i + 1] - j);
            }
        }
        return res;
    }
};

Python version

class Solution:
    def minimumScore(self, s: str, t: str) -> int:
        # 前后缀分解
        n, m = len(s), len(t)
        suf = [m] * (n + 1) # suf[i] = j 表示匹配后缀s[i:] 匹配了 t[j:]
        j = m - 1
        # 倒叙枚举分割位置,求后缀匹配
        for i in range(n - 1, -1, -1):
            if j >= 0 and s[i] == t[j]:
                j -= 1
            suf[i] = j + 1
        # 表示通过后缀匹配 去掉t[:suf[0]]
        res =  suf[0]
        # 正序枚举分割位置,求前缀匹配,并更新答案
        j = 0
        for i in range(n):
            if j < m and s[i] == t[j]:
                j += 1
                # 更新答案
                if suf[i+1] - j >= 0:
                    res = min(res, suf[i+1] - j)
        return res
posted @ 2023-02-12 21:48  Chenjq12  阅读(349)  评论(0)    收藏  举报