leetcode2565. 最少得分子序列[题解]

最少得分子序列
给你两个字符串 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 <= s.length, t.length <= 105
s 和 t 都只包含小写英文字母。

思路:开始我们可以发现一个性质,就是一个序列t是另一个序列s的子序列,那么这就代表序列t的子序列均是序列s的子序列。因此按照题目要求,删除\(left\)\(right\)中的任何数量字符得到的序列,均有一子序列是删除\(left\)\(right\)中的所有数量字符得到的序列。那么好了,我们为了方便,就把他全删了,这样留下前缀\(X\)与后缀\(Y\),我们只需要\(check\)字符串\(X+Y\)是否满足条件就ok。
如何\(check\)前后缀是否满足呢?利用子序列自动机就可以,子序列自动机可以看作在字符串s上每一个字符均有\(26\)个指针,\(f[i,j]\)表示字符串第\(i\)个位置的下一个字符为\('a'+j\)的下标。维护子序列自动机,实现看代码。然后利用二分来\(check\)因为具有同样的子序列关系。具体看代码(也可以用双指针,我认为二分答案好写,就用的二分)
\(Code\)

class Solution {
public:
    
    int a[100100][26],b[100100][26],pre[33],bep[33];
    void work(string s){
        int len = s.size() - 1;
        for(int i=0;i<=25;++i)pre[i] = len+1;
        for (int i = len; i >= 0; --i) {
        int id = s[i] - 'a';
        for(int j=0;j<=25;++j){
            a[i][j] = pre[j];
        }
        if(i == 0)break;
        pre[id] = i;
    }
    for (int i = 1; i <= len+1; ++i) {
        int id = s[i] - 'a';
        for (int j = 0; j <= 25; ++j) {
            b[i][j] = bep[j];
        }
        if(i == len+1)break;
        bep[id] = i;
    }
    }
    int lens,lent ;
    string ss,tt ;
    int arr[100010],brr[100010];
    bool check(int k){
        if(k == lent)return true;
        if(brr[k+1]!=0 and brr[k+1]!=lens+1)return true;
        if(arr[lent-k]!=0 and arr[lent-k]!=lens+1)return true;
        for(int i=1;;++i){
            int x = i,y = i+k+1;
            if(y>lent)break;
            if(brr[y]==0||brr[y]==lens+1)continue;
            if(arr[x]==0||arr[x]==lens+1)return false;
            int idx = arr[x],idy = brr[y];
            if(idx < idy){
                return true;
            }
        }
        return false;

    }
    int minimumScore(string s, string t) {
        s = "1" + s;
        t = "1" + t;ss = s;tt = t;     
        work(s);
        lens = s.size() - 1;
        lent = t.size() - 1;
        int idx = 0;
        for(int i=1;i<=lent;++i){
            int num = t[i] - 'a';
            idx = a[idx][num];
            arr[i] = idx;
            if(idx == 0||idx == lens+1)break;
        }
        idx = lens+1;
        for(int i=lent;i>=1;--i){
            int num = t[i] - 'a';
            idx = b[idx][num];
            brr[i] = idx;
            if(idx == 0||idx == lens+1)break;
        }
        int l = 0,r = lent;
        while(l < r){
            int mid = l + r >> 1;
            if(check(mid)){
                r = mid;
            }else l = mid + 1;
        }
        return l;
    }
};
posted @ 2023-03-02 16:27  xiaodangao  阅读(18)  评论(0编辑  收藏  举报