📜  门|门 CS 1997 |第 60 题(1)

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

题目介绍

本题为 "门门 CS 1997",是一个经典的算法题目,主要考察算法的优化能力,需要使用动态规划来解决问题。

题目描述

给定一个长度为 n 的字符串 s 和 m 个模式串 p1,p2,...,pm,求在 s 中能否找到一个子串,使得该子串恰好匹配其中的任意一个模式串。

输入格式

第一行包含两个整数 n,m,分别表示字符串 s 的长度和模式串的数量。

第二行包含一个长度为 n 的字符串 s。

接下来 m 行,每行一个字符串 pi,表示一个模式串。

输出格式

如果存在匹配的子串,输出 "YES",否则输出 "NO"。

注:匹配必须是精确匹配,不能有任何多余或缺少的字符。

数据范围
  • 1 ≤ n ≤ 10^5
  • 1 ≤ m ≤ 100
  • 所有字符串仅包含小写字母
输入样例
8 2
abcdeabc
abc
de
输出样例
YES
题解
算法一

我们可以枚举每一个模式串,并使用 KMP 算法进行匹配,时间复杂度是 O(nmlogm),不过可以通过优化 KMP 进一步优化时间复杂度。

时间复杂度:O(nmlogm)

空间复杂度:O(m)

代码片段:

def kmp(text, pattern):
    n, m = len(text), len(pattern)
    j = 0
    nxt = get_next(pattern)
    for i in range(n):
        while j > 0 and text[i] != pattern[j]:
            j = nxt[j-1]
        if text[i] == pattern[j]:
            j += 1
        if j == m:
            return True
    return False

def get_next(pattern):
    n = len(pattern)
    nxt = [0] * n
    j = 0
    for i in range(1, n):
        while j > 0 and pattern[i] != pattern[j]:
            j = nxt[j-1]
        if pattern[i] == pattern[j]:
            j += 1
        nxt[i] = j
    return nxt

def solve(text, patterns):
    for pattern in patterns:
        if kmp(text, pattern):
            return "YES"
    return "NO"

n, m = map(int, input().split())
text = input()
patterns = [input().strip() for _ in range(m)]
print(solve(text, patterns))
算法二

动态规划,我们可以定义 dp[i][j] 表示以 i 结尾的子串是否匹配第 j 个模式串,状态转移方程为:

if s[i] == p[j]:
    dp[i][j] = dp[i-1][j-1]
if s[i] != p[j]:
    dp[i][j] = False
dp[i][j] |= dp[i-1][j]

时间复杂度:O(nm)

空间复杂度:O(nm)

代码片段:

def solve(text, patterns):
    n, m = len(text), len(patterns)
    dp = [[False] * (m+1) for _ in range(n+1)]
    for i in range(n+1):
        dp[i][0] = True
    for i in range(1, n+1):
        for j in range(1, m+1):
            if text[i-1] == patterns[j-1]:
                dp[i][j] = dp[i-1][j-1]
            dp[i][j] |= dp[i-1][j]
    return "YES" if any(dp[n]) else "NO"

n, m = map(int, input().split())
text = input()
patterns = [input().strip() for _ in range(m)]
print(solve(text, patterns))
算法三

AC 自动机,可以将模式串插入到 AC 自动机中,然后在文本串上进行匹配。时间复杂度为 O(n+m+∑|pi|),其中 ∑|pi| 表示所有模式串的总长度。

时间复杂度:O(n+m+∑|pi|)

空间复杂度:O(∑|pi|)

代码片段:

class TrieNode:
    def __init__(self):
        self.children = {}
        self.fail = None
        self.is_end = False


class AC:
    def __init__(self):
        self.root = TrieNode()

    def insert(self, word):
        node = self.root
        for c in word:
            if c not in node.children:
                node.children[c] = TrieNode()
            node = node.children[c]
        node.is_end = True

    def build_fail(self):
        q = [self.root]
        while q:
            node = q.pop(0)
            for ch, child in node.children.items():
                if node == self.root:
                    child.fail = self.root
                else:
                    fail_node = node.fail
                    while fail_node is not None:
                        if ch in fail_node.children:
                            child.fail = fail_node.children[ch]
                            break
                        fail_node = fail_node.fail
                    if fail_node is None:
                        child.fail = self.root
                q.append(child)

    def search(self, text):
        node, res = self.root, []
        for i, c in enumerate(text):
            while node != self.root and c not in node.children:
                node = node.fail
            if c in node.children:
                node = node.children[c]
            temp = node
            while temp != self.root:
                if temp.is_end:
                    res.append((i, i-len(word)+1))
                temp = temp.fail
        return res


def solve(text, patterns):
    ac = AC()
    for pattern in patterns:
        ac.insert(pattern)
    ac.build_fail()
    res = ac.search(text)
    return "YES" if res else "NO"

n, m = map(int, input().split())
text = input().strip()
patterns = [input().strip() for _ in range(m)]
print(solve(text, patterns))
参考链接