📜  门| GATE CS 1996 |问题17(1)

📅  最后修改于: 2023-12-03 14:58:18.303000             🧑  作者: Mango

门 | GATE CS 1996 | 问题17

这道题目来自GATE CS 1996的考题,分值为2分。考察内容为哈希表和字符串处理。

题目描述

一个$n(n\leq 10^5)$个元素的字符串$S$,以及$m(m\leq 10^4)$个询问。每个询问$Q_i$包含一个字符串。对于每个$Q_i$,你需要判断$Q_i$是否是$S$中任意一个子串的前缀。换言之,你需要找到$S$中是否存在至少一个子串的前缀是$Q_i$。

解题思路

题目要求我们找到字符串中是否存在任意一个子串的前缀与询问中的字符串$Q_i$相符。考虑用哈希表来优化字符串的处理速度,由于我们要判断前缀是否相等,所以可以使用哈希前缀。即,对于字符串$S$,我们可以计算出它所有前缀的哈希值。然后对于每个询问$Q_i$,我们可以对其进行哈希,并遍历$S$中所有的前缀哈希值,判断是否与$Q_i$的哈希值相等即可。

在观察这个过程可以发现,我们可能在处理问题的过程中用到重复的子串哈希计算,因此可以使用预处理或者记忆化搜索等技巧来优化。

代码实现

以下是Python代码实现:

class HashTable:
    def __init__(self, s: str):
        self.s = s
        self.p = 31
        self.mod = 10 ** 9 + 9
        self.hash_table = self.generate_prefix_hash()

    def generate_prefix_hash(self) -> List[int]:
        n = len(self.s)
        hash_table = [0] * n
        prefix = 0
        p_pow = 1
        for i in range(n):
            prefix = (prefix + ord(self.s[i]) * p_pow) % self.mod
            p_pow = (p_pow * self.p) % self.mod
            hash_table[i] = prefix
        return hash_table

    def calculate_hash(self, s: str, l: int, r: int) -> int:
        p_pow, h = 1, 0
        for i in range(l, r + 1):
            h = (h + ord(s[i]) * p_pow) % self.mod
            p_pow = (p_pow * self.p) % self.mod
        return h

    def is_prefix_of_substring(self, q: str):
        q_hash = self.calculate_hash(q, 0, len(q) - 1)
        for i in range(len(self.s)):
            if i + len(q) > len(self.s):
                break
            s_hash = self.hash_table[i + len(q) - 1] if i == 0 else (self.hash_table[i + len(q) - 1] - self.hash_table[i - 1])
            if s_hash == q_hash:
                return True
        return False

以下是Java代码实现:

import java.math.BigInteger;
import java.util.*;

class HashTable {
    private static final BigInteger P = new BigInteger("31");
    private static final BigInteger MOD = new BigInteger("1000000009");
    private String s;
    private BigInteger[] hashTable;

    public HashTable(String s) {
        this.s = s;
        this.hashTable = this.generatePrefixHash();
    }

    private BigInteger[] generatePrefixHash() {
        int n = s.length();
        BigInteger[] hashTable = new BigInteger[n];
        BigInteger prefix = BigInteger.ZERO;
        BigInteger pPow = BigInteger.ONE;
        for (int i = 0; i < n; i++) {
            prefix = prefix.add(BigInteger.valueOf(s.charAt(i)).multiply(pPow)).mod(MOD);
            pPow = pPow.multiply(P).mod(MOD);
            hashTable[i] = prefix;
        }
        return hashTable;
    }

    private BigInteger calculateHash(String s, int l, int r) {
        BigInteger pPow = BigInteger.ONE;
        BigInteger h = BigInteger.ZERO;
        for (int i = l; i <= r; i++) {
            h = h.add(BigInteger.valueOf(s.charAt(i)).multiply(pPow)).mod(MOD);
            pPow = pPow.multiply(P).mod(MOD);
        }
        return h;
    }

    public boolean isPrefixOfSubstring(String q) {
        BigInteger qHash = calculateHash(q, 0, q.length() - 1);
        for (int i = 0; i < s.length(); i++) {
            if (i + q.length() > s.length()) {
                break;
            }
            BigInteger sHash = i == 0 ? hashTable[i + q.length() - 1] : hashTable[i + q.length() - 1].subtract(hashTable[i - 1]);
            if (sHash.compareTo(qHash) == 0) {
                return true;
            }
        }
        return false;
    }
}

以上是基于哈希表的题解及代码实现,希望对大家有所帮助。