跳至主要內容

序列自动机

大约 2 分钟

序列自动机

题目难度
$727. 最小窗口子序列open in new window 困难子序列自动机
792. 匹配子序列的单词数open in new window中等子序列自动机
2014. 重复 K 次的最长子序列open in new window困难子序列自动机
CF91Aopen in new windowrating 1500子序列自动机
CF1845Copen in new windowrating 1400子序列自动机

定义

$727. 最小窗口子序列

import java.util.Arrays;

public class Solution727 {
    public String minWindow(String s1, String s2) {
        int n = s1.length();
        int m = s2.length();

        int[] pos = new int[26];
        Arrays.fill(pos, n);

        // nxt[i][j] 表示 s[i] 右侧最近的字母 j 的位置
        int[][] nxt = new int[n][26];
        for (int i = n - 1; i >= 0; i--) {
            nxt[i] = pos.clone();
            pos[s1.charAt(i) - 'a'] = i;
        }

        String ans = "";
        for (int i0 = 0; i0 < n; i0++) {
            // 遍历所有 s 中的 t[0]
            if (s1.charAt(i0) == s2.charAt(0)) {
                int i = i0;
                // 匹配 t 中的字符
                for (int j = 1; j < m; j++) {
                    i = nxt[i][s2.charAt(j) - 'a'];
                    if (i == n) {
                        return ans;
                    }
                }
                String w = s1.substring(i0, i + 1);
                if (ans.equals("") || w.length() < ans.length()) {
                    ans = w;
                }
            }
        }
        return ans;
    }
}

792. 匹配子序列的单词数

import java.util.Arrays;

public class Solution792 {
    public int numMatchingSubseq(String s, String[] words) {
        int n = s.length();

        // 子序列自动机
        int[] pos = new int[26];
        Arrays.fill(pos, -1);
        int[][] nxt = new int[n + 1][26];
//        nxt[n] = pos.clone();
        System.arraycopy(pos, 0, nxt[n], 0, 26);
        for (int i = n - 1; i >= 0; i--) {
            pos[s.charAt(i) - 'a'] = i;
//            nxt[i] = pos.clone();
            System.arraycopy(pos, 0, nxt[i], 0, 26);
        }

        int ans = words.length;
        for (String word : words) {
            int pre = 0;
            for (int j = 0; j < word.length(); j++) {
                pre = nxt[pre][word.charAt(j) - 'a'];
                if (pre < 0) {
                    ans--;
                    break;
                }
                pre++;
            }
        }
        return ans;
    }
}

CF1845C

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Scanner;

public class CF1845C {
    static String s, l, r;
    static int m;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in, StandardCharsets.UTF_8);
        int t = scanner.nextInt();
        while (t-- > 0) {
            s = scanner.next();
            m = scanner.nextInt();
            l = scanner.next();
            r = scanner.next();
            System.out.println(solve());
        }
    }

    // https://codeforces.com/contest/1845/submission/211453965
    private static String solve() {
        int n = s.length();

        // 子序列自动机
        // 预处理 s[i] 下一个 '0'~'9' 出现的位置
        int[][] next = new int[n + 1][10];
        Arrays.fill(next[n], n);
        for (int i = n - 1; i >= 0; i--) {
            next[i] = next[i + 1].clone();
            next[i][s.charAt(i) - '0'] = i;
        }

        int cur = -1;
        for (int i = 0; i < m && cur < n; i++) {
            int nxt = 0;
            for (int j = l.charAt(i) - '0'; j <= r.charAt(i) - '0'; j++) {
                nxt = Math.max(nxt, next[cur + 1][j]);
            }
            cur = nxt;
        }
        return cur == n ? "YES" : "NO";
    }
}

(全文完)