Queries to check if string B exists as substring in string A

Given two strings A, B and some queries consisting of an integer i, the task is to check whether the sub-string of A starting from index i and ending at index i + length(B) – 1 equals B or not. If equal then print Yes else print No. Note that i + length(B) will always be smaller than length(A).

Examples:

Input: A = “abababa”, B = “aba”, q[] = {0, 1, 2, 3}
Output:
Yes
No
Yes
No
a[0-2] = “aba” = b (both are equal)
a[1-3] = “bab” != b
a[2-4] = “aba” = b
a[3-5] = “bab” !=b



Input: A = “GeeksForGeeks”, B = “Geeks”, q[] = {0, 5, 8}
Output:
Yes
No
Yes

A simple approach will be to compare the strings character by character for every query which will take O(length(B)) time to answer each query.

Efficient approach: We will optimize the query processing using rolling hash algorithm.
First, we will find hash value of string B. Then, using rolling hash technique, we will do the pre-processing of string A.
Let’s suppose we created an array hash_A. Then ith element of this array will store.

((a[0] – 97) + (a[1] – 97) * d + (a[2] – 97) * d2 + ….. + (a[i] – 97) * di) % mod
where d is the multiplier in rolling-hash.

We will use this to find hash of the sub-string of A.
Hash of sub-string of A starting from i can be found as (hash_a[i + len_b – 1] – hash_a[i – 1]) / di or more specifically

((hash_a[i + len_b – 1] – hash_a[i – 1] + 2 * mod) * mi(di)) % mod

Thus, using this we can answer each query in O(1).

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation of the approach
#include <bits/stdc++.h>
#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;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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 */

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# 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

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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 */

chevron_right


Output:

Yes
No
Yes
No

Note: For simplicity, we have used only one hash function. Use double/triple hash to eliminate any chance of collision and more accurate result.



My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.



Improved By : princiraj1992, sanjeev2552