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.

The above question can be solved by using DP also, below is the java code.

Java

filter_none

edit
close

play_arrow

link
brightness_4
code

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

chevron_right


Output

true
false
true

Time Complexity: O(M*N)

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.




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.