📜  查询字符串B是否作为字符串A中的子字符串存在

📅  最后修改于: 2021-04-27 19:40:13             🧑  作者: Mango

给定两个字符串AB以及一些由整数i组成的查询,任务是检查A的子字符串是否从索引i开始并以索引i + length(B)– 1结束,是否等于B。如果相等,则打印“是”,否则打印“否”请注意i + length(B)将始终小于length(A)

例子:

一种简单的方法将是字符串逐个的每个查询,这将花费O(长度(B))的时间来回答每个查询进行比较。

高效的方法:我们将使用滚动哈希算法优化查询处理。
首先,我们将找到字符串B的哈希值。然后,使用滚动哈希技术,将对字符串A进行预处理。
假设我们创建了一个数组hash_A。然后,该数组的第i个元素将存储。

我们将使用它来查找A的子字符串的哈希。

从i开始的A子字符串的哈希可以找到(hash_a [i + len_b – 1] – hash_a [i – 1])/ d i或更具体地

因此,使用它我们可以回答O(1)中的每个查询。

下面是上述方法的实现:

C++
// C++ implementation of the approach
#include 
#define mod 3803
#define d 26
using namespace std;
 
int hash_b;
int* hash_a;
int* mul;
 
// Function to return the modular inverse
// using Fermat's little theorem
int mi(int x)
{
    int p = mod - 2;
    int s = 1;
    while (p != 1) {
        if (p % 2 == 1)
            s = (s * x) % mod;
        x = (x * x) % mod;
        p /= 2;
    }
 
    return (s * x) % mod;
}
 
// Function to generate hash
void genHash(string& a, string& b)
{
    // To store prefix-sum
    // of rolling hash
    hash_a = new int[a.size()];
 
    // Multiplier for different values of i
    mul = new int[a.size()];
 
    // Generating hash value for string b
    for (int i = b.size() - 1; i >= 0; i--)
        hash_b = (hash_b * d + (b[i] - 97)) % mod;
 
    // Generating prefix-sum of hash of a
    mul[0] = 1;
    hash_a[0] = (a[0] - 97) % mod;
    for (int i = 1; i < a.size(); i++) {
        mul[i] = (mul[i - 1] * d) % mod;
        hash_a[i]
            = (hash_a[i - 1] + mul[i] * (a[i] - 97)) % mod;
    }
}
 
// Function that returns true if the
// required sub-string in a is equal to b
bool checkEqual(int i, int len_a, int len_b)
{
    // To store hash of required
    // sub-string of A
    int x;
 
    // If i = 0 then
    // requires hash value
    if (i == 0)
        x = hash_a[len_b - 1];
 
    // Required hash if i != 0
    else {
        x = (hash_a[i + len_b - 1] - hash_a[i - 1]
             + 2 * mod)
            % mod;
        x = (x * mi(mul[i])) % mod;
    }
 
    // Comparing hash with hash of B
    if (x == hash_b)
        return true;
 
    return false;
}
 
// Driver code
int main()
{
    string a = "abababababa";
    string b = "aba";
 
    // Generating hash
    genHash(a, b);
 
    // Queries
    int queries[] = { 0, 1, 2, 3 };
    int q = sizeof(queries) / sizeof(queries[0]);
 
    // Perform queries
    for (int i = 0; i < q; i++) {
        if (checkEqual(queries[i], a.size(), b.size()))
            cout << "Yes\n";
        else
            cout << "No\n";
    }
 
    return 0;
}


Java
// Java implementation of the approach
import java.util.*;
 
class GFG {
 
    static int mod = 3803;
    static int d = 26;
 
    static int hash_b;
    static int[] hash_a;
    static int[] mul;
 
    // Function to return the modular inverse
    // using Fermat's little theorem
    static int mi(int x)
    {
        int p = mod - 2;
        int s = 1;
        while (p != 1) {
            if (p % 2 == 1) {
                s = (s * x) % mod;
            }
            x = (x * x) % mod;
            p /= 2;
        }
 
        return (s * x) % mod;
    }
 
    // Function to generate hash
    static void genHash(char[] a, char[] b)
    {
        // To store prefix-sum
        // of rolling hash
        hash_a = new int[a.length];
 
        // Multiplier for different values of i
        mul = new int[a.length];
 
        // Generating hash value for string b
        for (int i = b.length - 1; i >= 0; i--) {
            hash_b = (hash_b * d + (b[i] - 97)) % mod;
        }
 
        // Generating prefix-sum of hash of a
        mul[0] = 1;
        hash_a[0] = (a[0] - 97) % mod;
        for (int i = 1; i < a.length; i++) {
            mul[i] = (mul[i - 1] * d) % mod;
            hash_a[i]
                = (hash_a[i - 1] + mul[i] * (a[i] - 97))
                  % mod;
        }
    }
 
    // Function that returns true if the
    // required sub-string in a is equal to b
    static boolean checkEqual(int i, int len_a, int len_b)
    {
        // To store hash of required
        // sub-string of A
        int x;
 
        // If i = 0 then
        // requires hash value
        if (i == 0) {
            x = hash_a[len_b - 1];
        }
        // Required hash if i != 0
        else {
            x = (hash_a[i + len_b - 1] - hash_a[i - 1]
                 + 2 * mod)
                % mod;
            x = (x * mi(mul[i])) % mod;
        }
 
        // Comparing hash with hash of B
        if (x == hash_b) {
            return true;
        }
 
        return false;
    }
 
    // Driver code
    public static void main(String[] args)
    {
        String a = "abababababa";
        String b = "aba";
 
        // Generating hash
        genHash(a.toCharArray(), b.toCharArray());
 
        // Queries
        int queries[] = { 0, 1, 2, 3 };
        int q = queries.length;
 
        // Perform queries
        for (int i = 0; i < q; i++) {
            if (checkEqual(queries[i], a.length(),
                           b.length())) {
                System.out.println("Yes");
            }
            else {
                System.out.println("No");
            }
        }
    }
}
 
/* This code is contributed by PrinciRaj1992 */


Python3
# Python3 implementation of the approach
mod = 3803
d = 26
 
hash_b = 0
hash_a = []
mul = []
 
# Function to return the modular inverse
# using Fermat's little theorem
 
 
def mi(x):
    global mod
    p = mod - 2
    s = 1
    while p != 1:
        if p % 2 == 1:
            s = (s * x) % mod
 
        x = (x * x) % mod
        p //= 2
 
    return (s * x) % mod
 
# Function to generate hash
 
 
def genHash(a, b):
    global hash_b, hash_a, mul, d, mod
 
    # To store prefix-sum
    # of rolling hash
    hash_a = [0] * len(a)
 
    # Multiplier for different values of i
    mul = [0] * len(a)
 
    # Generating hash value for string b
    for i in range(len(b) - 1, -1, -1):
        hash_b = (hash_b * d +
                  (ord(b[i]) - 97)) % mod
 
    # Generating prefix-sum of hash of a
    mul[0] = 1
    hash_a[0] = (ord(a[0]) - 97) % mod
    for i in range(1, len(a)):
        mul[i] = (mul[i - 1] * d) % mod
        hash_a[i] = (hash_a[i - 1] + mul[i] *
                     (ord(a[i]) - 97)) % mod
 
# Function that returns true if the
# required sub-string in a is equal to b
 
 
def checkEqual(i, len_a, len_b):
    global hash_b, hash_a, mul, d, mod
 
    # To store hash of required
    # sub-string of A
    x = -1
 
    # If i = 0 then
    # requires hash value
    if i == 0:
        x = hash_a[len_b - 1]
 
    # Required hash if i != 0
    else:
        x = (hash_a[i + len_b - 1] -
             hash_a[i - 1] + 2 * mod) % mod
        x = (x * mi(mul[i])) % mod
 
    # Comparing hash with hash of B
    if x == hash_b:
        return True
 
    return False
 
 
# Driver Code
if __name__ == "__main__":
    a = "abababababa"
    b = "aba"
 
    # Generating hash
    genHash(a, b)
 
    # Queries
    queries = [0, 1, 2, 3]
    q = len(queries)
 
    # Perform queries
    for i in range(q):
        if checkEqual(queries[i], len(a), len(b)):
            print("Yes")
        else:
            print("No")
 
# This code is contributed by
# sanjeev2552


C#
// C# implementation of the approach
using System;
 
class GFG {
 
    static int mod = 3803;
    static int d = 26;
 
    static int hash_b;
    static int[] hash_a;
    static int[] mul;
 
    // Function to return the modular inverse
    // using Fermat's little theorem
    static int mi(int x)
    {
        int p = mod - 2;
        int s = 1;
        while (p != 1) {
            if (p % 2 == 1) {
                s = (s * x) % mod;
            }
            x = (x * x) % mod;
            p /= 2;
        }
 
        return (s * x) % mod;
    }
 
    // Function to generate hash
    static void genHash(char[] a, char[] b)
    {
        // To store prefix-sum
        // of rolling hash
        hash_a = new int[a.Length];
 
        // Multiplier for different values of i
        mul = new int[a.Length];
 
        // Generating hash value for string b
        for (int i = b.Length - 1; i >= 0; i--) {
            hash_b = (hash_b * d + (b[i] - 97)) % mod;
        }
 
        // Generating prefix-sum of hash of a
        mul[0] = 1;
        hash_a[0] = (a[0] - 97) % mod;
        for (int i = 1; i < a.Length; i++) {
            mul[i] = (mul[i - 1] * d) % mod;
            hash_a[i]
                = (hash_a[i - 1] + mul[i] * (a[i] - 97))
                  % mod;
        }
    }
 
    // Function that returns true if the
    // required sub-string in a is equal to b
    static Boolean checkEqual(int i, int len_a, int len_b)
    {
        // To store hash of required
        // sub-string of A
        int x;
 
        // If i = 0 then
        // requires hash value
        if (i == 0) {
            x = hash_a[len_b - 1];
        }
        // Required hash if i != 0
        else {
            x = (hash_a[i + len_b - 1] - hash_a[i - 1]
                 + 2 * mod)
                % mod;
            x = (x * mi(mul[i])) % mod;
        }
 
        // Comparing hash with hash of B
        if (x == hash_b) {
            return true;
        }
 
        return false;
    }
 
    // Driver code
    public static void Main(String[] args)
    {
        String a = "abababababa";
        String b = "aba";
 
        // Generating hash
        genHash(a.ToCharArray(), b.ToCharArray());
 
        // Queries
        int[] queries = { 0, 1, 2, 3 };
        int q = queries.Length;
 
        // Perform queries
        for (int i = 0; i < q; i++) {
            if (checkEqual(queries[i], a.Length,
                           b.Length)) {
                Console.WriteLine("Yes");
            }
            else {
                Console.WriteLine("No");
            }
        }
    }
}
 
/* This code contributed by PrinciRaj1992 */


Java
import java.io.*;
import java.util.*;
import java.lang.*;
import java.io.*;
 
public class GFG
{
    private static void
    substringCheck(String stra, String strb, int[] query)
    {
 
        // Dp Array
        int[][] matrix
            = new int[strb.length()][stra.length()];
       
        // String to character array
        char[] charCrr = stra.toCharArray();
        char[] charRrr = strb.toCharArray();
 
        // initialize matrix with 1
        for (int c = 0; c < stra.length(); c++)
        {
            if (charRrr[0] == charCrr)
            {
                matrix[0] = 1;
            }
        }
 
        // for r from 1 to string length
        for (int r = 1; r < charRrr.length; r++)
        {
            char ch = charRrr[r];
 
            // for c from 1 b string length
            for (int c = 1; c < charCrr.length; c++)
            {
                if (ch == charCrr
                    && matrix[r - 1] == 1)
                {
                    matrix[r] = 1;
                }
            }
        }
 
        // For every query
        for (int q : query)
        {
            int matLoc = (q + (strb.length() - 1));
            if (matLoc >= stra.length()) {
                System.out.println(false);
            }
            else
            {
                // print true
                if (matrix[strb.length() - 1][matLoc]
                    == 1)
                {
                    System.out.println(true);
                }
                else
                {
                    // print false
                    System.out.println(false);
                }
            }
        }
 
    }
   
    // Driver Code
    public static void main(String[] args)
    {
        String stra = "GeeksForGeeks";
        String strb = "Geeks";
        int[] query = { 0,5,8 };
        substringCheck(stra, strb, query);
    }
 
} // class
// Code contibuted by Swapnil Gupta


输出
Yes
No
Yes
No

注意:为简单起见,我们仅使用了一个哈希函数。使用double / triple hash(双/三重哈希)消除冲突的机会和更准确的结果。

上面的问题也可以通过使用DP来解决,下面是Java代码。

Java

import java.io.*;
import java.util.*;
import java.lang.*;
import java.io.*;
 
public class GFG
{
    private static void
    substringCheck(String stra, String strb, int[] query)
    {
 
        // Dp Array
        int[][] matrix
            = new int[strb.length()][stra.length()];
       
        // String to character array
        char[] charCrr = stra.toCharArray();
        char[] charRrr = strb.toCharArray();
 
        // initialize matrix with 1
        for (int c = 0; c < stra.length(); c++)
        {
            if (charRrr[0] == charCrr)
            {
                matrix[0] = 1;
            }
        }
 
        // for r from 1 to string length
        for (int r = 1; r < charRrr.length; r++)
        {
            char ch = charRrr[r];
 
            // for c from 1 b string length
            for (int c = 1; c < charCrr.length; c++)
            {
                if (ch == charCrr
                    && matrix[r - 1] == 1)
                {
                    matrix[r] = 1;
                }
            }
        }
 
        // For every query
        for (int q : query)
        {
            int matLoc = (q + (strb.length() - 1));
            if (matLoc >= stra.length()) {
                System.out.println(false);
            }
            else
            {
                // print true
                if (matrix[strb.length() - 1][matLoc]
                    == 1)
                {
                    System.out.println(true);
                }
                else
                {
                    // print false
                    System.out.println(false);
                }
            }
        }
 
    }
   
    // Driver Code
    public static void main(String[] args)
    {
        String stra = "GeeksForGeeks";
        String strb = "Geeks";
        int[] query = { 0,5,8 };
        substringCheck(stra, strb, query);
    }
 
} // class
// Code contibuted by Swapnil Gupta
输出
true
false
true

时间复杂度: O(M * N)