Keywords Filter

218 周

题目1 : Keywords Filter

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

You are given a string S which consists of only lower case letters and N keyword W1, W2, ... WN which also consists of only lower case letters. For each appearance of a keyword in S you need to change the letters matching the keyword into '*'.

Assume S = "abcxyzabcd" and keywords are {"abc", "cd"}, the filtered S' will be "***xyz****".

输入

The first line contains an integer N. (1 <= N <= 1000)

The following N lines each contains a keyword. The total length of the keywords is no more than 100000.

The last line contains the string S. The length of S is no more than 100000.

输出

The filtered string.

样例输入

2  
abc  
cd  
abcxyzabcd

样例输出

***xyz****

Tire 树

import java.util.*;

public class Main {
//字典树结点
class TrieNode {
    char ch;//此值仅用于调试
    TrieNode[] sons;
    TrieNode fail;
    char[] value;//如果是terminal,则nodeValue不为空

    boolean isTerminal() {
        return value != null;
    }

    TrieNode(char ch) {
        this.ch = ch;
    }
}

//命中:pos表示命中的最后位置,s表示命中的单词
class Hit {
    int beg;
    char[] s;

    Hit(char[] s, int beg) {
        this.s = s;
        this.beg = beg;
    }
}


class Trie {
    TrieNode root = new TrieNode(' ');

    Trie(char[][] patterns) {
        for (char[] i : patterns) insert(i);
        build();
    }

    void insert(char[] s) {
        TrieNode now = root;
        for (char c : s) {
            //遇山开路,遇水铺桥
            if (now.sons == null) {
                now.sons = new TrieNode[26];
            }
            if (now.sons[c - 'a'] == null) {
                now.sons[c - 'a'] = new TrieNode(c);
            }
            now = now.sons[c - 'a'];
        }
        now.value = s;
    }

    List<Hit> query(char[] s) {
        List<Hit> hits = new ArrayList<>(maxn);
        TrieNode now = null;
        for (int i = 0; i < s.length; i++) {
            char c = s[i];
            if (now == null) now = root;
            while (now != root) {
                if (now.sons == null || now.sons[c - 'a'] == null) {
                    now = now.fail;
                    continue;
                }
                break;
            }
            now = now.sons[c - 'a'];
            if (now == null) {
                now = root;
                continue;
            }
            if (now.isTerminal()) hits.add(new Hit(now.value, i - now.value.length + 1));
        }
        return hits;
    }

    TrieNode getFail(TrieNode pre, int ch) {
        while (pre != root) {
            if (pre.sons != null && pre.sons[ch] != null)
                break;
            pre = pre.fail;
        }
        if (pre.sons[ch] != null) return pre.sons[ch];
        return root;
    }

    void build() {
        Queue<TrieNode> q = new LinkedList<>();
        root.fail = root;
        //初始化第一层,假设一开始没命中,之后应该怎么办
        /**
         * 某种程度上,AC自动机相当于动态规划
         * */
        for (TrieNode i : root.sons) {
            if (i != null) {
                q.add(i);
                i.fail = root;
            }
        }
        while (!q.isEmpty()) {
            TrieNode now = q.poll();
            if (now.sons == null) continue;
            for (int i = 0; i < now.sons.length; i++) {
                if (now.sons[i] == null) continue;
                now.sons[i].fail = getFail(now.fail, i);
                //如果我不是终点,我需要把自己设置成终点
                /**
                 * 此处非常关键
                 * */
                if (now.sons[i].fail.isTerminal() && !now.sons[i].isTerminal()) {
                    now.sons[i].value = now.sons[i].fail.value;
                }
                q.add(now.sons[i]);
            }
        }

//        show(root);
    }
}

class Node {
    int x, type;

    Node(int x, int type) {
        this.x = x;
        this.type = type;
    }
}

final int maxn = 1007;
int[] lens;

Main() {
    Scanner cin = new Scanner(System.in);
    int n = cin.nextInt();
    lens = new int[n];
    char[][] patterns = new char[n][];
    for (int i = 0; i < n; i++) {
        patterns[i] = cin.next().toCharArray();
    }
    Trie tree = new Trie(patterns);
    char[] s = cin.next().toCharArray();
    List<Hit> hits = tree.query(s);
    List<Node> nodes = new ArrayList<>(2 * hits.size());
    for (Hit i : hits) {
        nodes.add(new Node(i.beg, 1));
        nodes.add(new Node(i.beg + i.s.length, -1));
    }
    nodes.sort(Comparator.comparing(x -> x.x));
    StringBuilder builder = new StringBuilder();
    int in = 0;
    int j = 0;
    for (int i = 0; i < s.length; i++) {
        while (j < nodes.size() && nodes.get(j).x <= i) {
            in += nodes.get(j).type;
            j++;
        }
        if (in == 0) builder.append(s[i]);
        else builder.append('*');
    }
    System.out.println(builder.toString());
}

public static void main(String[] args) {
    new Main();
}
}

猜你喜欢

转载自blog.csdn.net/weixin_38970751/article/details/85460119