Open In App

Palindrome Substring Queries

Last Updated : 27 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Given a string str of length n and a 2d array queries[][], where each query queries[i] is of type [i, j]. For each query, your task is to check if the substring str[i:j] is a palindrome.

Examples : 

Input: str = “abaaabaaaba”
queries[][] = [ [0, 10], [5, 8], [2, 5], [5, 9] ]
Output: 1 0 0 1
Explanation: Lets process all the queries one by one:
a. [0, 10]: The substring is “abaaabaaaba” which is a palindrome.
b. [5, 8]: The substring is “baaa” which is not a palindrome.
c. [2, 5]: The substring is “aaab” which is not a palindrome. 
d. [5, 9]: The substring is “baaab” which is a palindrome. 

Input: str = “abdcaaa”
queries[][] = [ [0, 1], [2, 2], [4, 6] ]
Output: 0 1 1
Explanation: Lets process all the queries one by one:
a. [0, 1]: The substring is “ab” which is not a palindrome.
b. [2, 2]: The substring is “baaa” which is not a palindrome.
c. [4, 6]: The substring is “aaa” which is a palindrome. 

[Naive Approach] – O(n * q) Time and O(1) Space

The idea is to process each query one-by-one and for each query [i, j] use for loop to check if the substring str[i…j] is palindrome.

C++
#include <bits/stdc++.h>
using namespace std;

// function to check if a substring is a palindrome
bool isPalindrome(string str, int start, int end) {
    while (start < end) {
        if (str[start] != str[end]) {
            return false;
        }
        start++;
        end--;
    }
    return true;
}

// function to check if the substring 
// is a palindrome for each query
vector<int> palindromeQueries(string str, 
    vector<vector<int>>& queries) {

    // to store the results
    vector<int> result;
    for (auto query : queries) {
        int start = query[0];
        int end = query[1];

        // check if the substring is a palindrome
        if (isPalindrome(str, start, end)) {
            result.push_back(1);
        } else {
            result.push_back(0);
        }
    }
    return result;
}

int main() {
    string str = "abaaabaaaba";
    vector<vector<int>> queries = 
    {{0, 10}, {5, 8}, {2, 5}, {5, 9}};
    vector<int> res = 
    palindromeQueries(str, queries);
    for(auto i: res) {
        cout << i << " ";
    }
    return 0;
}
Java
import java.util.*;

public class GfG {

    // function to check if a substring is a palindrome
    static boolean isPalindrome(String str, int start, int end) {
        while (start < end) {
            if (str.charAt(start) != str.charAt(end)) {
                return false;
            }
            start++;
            end--;
        }
        return true;
    }

    // function to check if the substring 
    // is a palindrome for each query
    static List<Integer> palindromeQueries(String str, List<int[]> queries) {

        // to store the results
        List<Integer> result = new ArrayList<>();
        for (int[] query : queries) {
            int start = query[0];
            int end = query[1];

            // check if the substring is a palindrome
            if (isPalindrome(str, start, end)) {
                result.add(1);
            } else {
                result.add(0);
            }
        }
        return result;
    }

    public static void main(String[] args) {
        String str = "abaaabaaaba";
        List<int[]> queries = Arrays.asList(
            new int[]{0, 10}, new int[]{5, 8}, 
            new int[]{2, 5}, new int[]{5, 9}
        );
        List<Integer> res = palindromeQueries(str, queries);
        for (int i : res) {
            System.out.print(i + " ");
        }
    }
}
Python
# function to check if a substring is a palindrome
def isPalindrome(string, start, end):
    while start < end:
        if string[start] != string[end]:
            return False
        start += 1
        end -= 1
    return True

# function to check if the substring 
# is a palindrome for each query
def palindromeQueries(string, queries):

    # to store the results
    result = []
    for query in queries:
        start = query[0]
        end = query[1]

        # check if the substring is a palindrome
        if isPalindrome(string, start, end):
            result.append(1)
        else:
            result.append(0)
    return result

if __name__ == "__main__":
    string = "abaaabaaaba"
    queries = [[0, 10], [5, 8], [2, 5], [5, 9]]
    res = palindromeQueries(string, queries)
    print(" ".join(map(str, res)))
C#
using System;
using System.Collections.Generic;

public class GfG {

    // function to check if a substring is a palindrome
    static bool IsPalindrome(string str, int start, int end) {
        while (start < end) {
            if (str[start] != str[end]) {
                return false;
            }
            start++;
            end--;
        }
        return true;
    }

    // function to check if the substring 
    // is a palindrome for each query
    static List<int> PalindromeQueries(string str, List<int[]> queries) {

        // to store the results
        List<int> result = new List<int>();
        foreach (var query in queries) {
            int start = query[0];
            int end = query[1];

            // check if the substring is a palindrome
            if (IsPalindrome(str, start, end)) {
                result.Add(1);
            } else {
                result.Add(0);
            }
        }
        return result;
    }

    public static void Main(string[] args) {
        string str = "abaaabaaaba";
        List<int[]> queries = new List<int[]> {
            new int[] {0, 10}, new int[] {5, 8}, 
            new int[] {2, 5}, new int[] {5, 9}
        };
        List<int> res = PalindromeQueries(str, queries);
        Console.WriteLine(string.Join(" ", res));
    }
}
JavaScript
// function to check if a substring is a palindrome
function isPalindrome(str, start, end) {
    while (start < end) {
        if (str[start] !== str[end]) {
            return false;
        }
        start++;
        end--;
    }
    return true;
}

// function to check if the substring 
// is a palindrome for each query
function palindromeQueries(str, queries) {

    // to store the results
    let result = [];
    for (let query of queries) {
        let start = query[0];
        let end = query[1];

        // check if the substring is a palindrome
        if (isPalindrome(str, start, end)) {
            result.push(1);
        } else {
            result.push(0);
        }
    }
    return result;
}

function main() {
    let str = "abaaabaaaba";
    let queries = [[0, 10], [5, 8], [2, 5], [5, 9]];
    let res = palindromeQueries(str, queries);
    console.log(res.join(" "));
}

main();

Output
1 0 0 1 

[Expected Approach] – Using Cumulative Hash – O(n + q) Time and O(n) Space

The idea is similar to Rabin Karp string matching. We use string hashing. What we do is that we calculate cumulative hash values of the string in the original string as well as the reversed string in two arrays- prefix[] and suffix[].

How to calculate the cumulative hash values?
Suppose our string is str[], then the cumulative hash function to fill our prefix[] array used is- 

prefix[0] = 0 
prefix[i] = str[0] + str[1] * 101 + str[2] * 1012 + …… + str[i-1] * 101i-1
For example, take the string- “abaaabxyaba”
prefix[0] = 0 
prefix[1] = 97 (ASCII Value of ‘a’ is 97) 
prefix[2] = 97 + 98 * 101 
prefix[3] = 97 + 98 * 101 + 97 * 1012 
……………………… 
……………………… 
prefix[11] = 97 + 98 * 101 + 97 * 1012 + ……..+ 97 * 10110 

Now the reason to store in that way is that we can easily find the hash value of any substring in O(1) time using

hash(L, R) = prefix[R+1] – prefix[L]

For example, hash (1, 5) = hash (“baaab”) = prefix[6] – prefix[1] = 98 * 101 + 97 * 1012 + 97 * 1013 + 97 * 1014 + 98 * 1015 = 1040184646587 [. We will use this weird value later to explain what’s happening].

Similar to this we will fill our suffix[] array as- 

suffix[0] = 0 
suffix[i] = str[n-1] + str[n-2] * 1011 + str[n-3] * 1012 + …… + str[n-i] * 101i-1
For example, take the string- “abaaabxyaba”
suffix[0] = 0 
suffix[1] = 97 (ASCII Value of ‘a’ is 97) 
suffix[2] = 97 + 98 * 101 
suffix[3] = 97 + 98 * 101 + 97 * 1012 
……………………… 
……………………… 
suffix[11] = 97 + 98 * 101 + 97 * 1012 + ……..+ 97 * 10110
Now the reason to store in that way is that we can easily find the reverse hash value of any substring in O(1) time using  

reverse_hash(L, R) = hash (R, L) = suffix[n-L] – suffix[n-R-1]

where n = length of string

For “abaaabxyaba”, n = 11 
reverse_hash(1, 5) = reverse_hash(“baaab”) = hash(“baaab”) [Reversing “baaab” gives “baaab”]
hash(“baaab”) = suffix[11-1] – suffix[11-5-1] = suffix[10] – suffix[5] = 98 * 1015 + 97 * 1016 + 97 * 1017 + 97 * 1018 + 98 * 1019 = 108242031437886501387 

Now there doesn’t seem to be any relationship between these two weird integers – 1040184646587 and 108242031437886501387 
Think again. Is there any relation between these two massive integers ?
Yes, there is and this observation is the core of this program/article. 

1040184646587 * 1014 = 108242031437886501387 

Try thinking about this and you will find that any substring starting at index- L and ending at index- R (both inclusive) will be a palindrome if 

(prefix[R + 1] – prefix[L]) / (101L) = (suffix [n – L] – suffix [n – R- 1] ) / (101n – R – 1

The rest part is just implementation.
The function computerPowers() in the program computes the powers of 101 using dynamic programming.

Overflow Issues: 

As, we can see that the hash values and the reverse hash values can become huge for even the small strings of length – 8. Since C and C++ doesn’t provide support for such large numbers, so it will cause overflows. To avoid this we will take modulo of a prime (a prime number is chosen for some specific mathematical reasons). We choose the biggest possible prime which fits in an integer value. The best such value is 1000000007. Hence all the operations are done modulo 1000000007. However, Java and Python has no such issues and can be implemented without the modulo operator. The fundamental modulo operations which are used extensively in the program are listed below. 

1) Addition (a + b) %M = (a %M + b % M) % M 

2) Multiplication  (a * b) % M = (a * b) % M 
This property is used by modPow() function which computes power of a number modulo M 

3) Mixture of addition and multiplication
 (a * x + b * y + c) % M = ( (a * x) % M +(b * y) % M+ c % M ) % M 

4) Subtraction
(a – b) % M = (a % M – b % M + M) % M [Correct] 
(a – b) % M = (a % M – b % M) % M [Wrong] 

5) Division
(a / b) % M = (a * MMI(b)) % M
Where MMI() is a function to calculate Modulo Multiplicative Inverse. In our program this is implemented by the function- findMMI(). 

Below are the detailed steps.

  • Given a string str[], we compute the prefix hash as:
    prefix[0] = 0
    [Tex]prefix[i] = str[0] + str[1] * 101 + str[2] * 101 ^ 2 + … + str[i – 1] * 101 ^ {i – 1}[/Tex]
  • Using prefix hashing, the hash value of a substring str[L:R] can be found as:
    [Tex]hash(L, R) = prefix[R + 1] – prefix[L][/Tex]
  • Similar to this, we compute the suffix hash as:
    suffix[0] = 0
    [Tex]suffix[i] = str[n – 1] + str[n – 2] * 101 + str[n – 3] * 101 ^ 2 + … + str[n – i] * 101 ^ {i – 1}[/Tex]
  • Using suffix hashing, the reverse hash of a substring str[L:R] can be found as:
    [Tex]reverseHash(L, R) = suffix[n – L] – suffix[n – R – 1][/Tex]
  • A substring str[L:R] is a palindrome if:
    [Tex]prefix[R + 1] – prefix[L] / 101 ^ L = suffix[n – L] – suffix[n – R – 1] / 101 ^ {n – R – 1}[/Tex]
  • This means the hash values must match after adjusting for position shifts.
  • To avoid integer overflow, use mod 1e9 + 7. The mod operation has following properties:
    • Addition: (a + b) % mod = ((a % mod) + (b % mod)) % mod
    • Multiplication: (a * b) % mod = ((a % mod) * (b % mod)) % mod
    • Subtraction: (a – b) % mod = ((a % mod) – (b % mod) + mod) % mod
    • Division: Used modular multiplicative inverse via Fermat’s Theorem.
  • Precompute powers of 101 using dynamic programming (computePowers()).
  • Build prefix and suffix hash tables.
C++
#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define int long long int

// function to calculate the prefix hash
vector<int> prefixHash(string &str, vector<int> &power) {
    int n = str.size();
    vector<int> prefix(n + 1);
    prefix[0] = 0;
    prefix[1] = str[0] - 'a' + 1;

    for (int i = 2; i <= n; i++) {
        prefix[i] = (prefix[i - 1] + 
        (str[i - 1] - 'a' + 1) * power[i - 1]) % mod;
    }
    return prefix;
}

// function to calculate the suffix hash
vector<int> suffixHash(string &str, vector<int> &power) {
    int n = str.size();
    vector<int> suffix(n + 1);
    suffix[0] = 0;
    suffix[1] = str[n - 1] - 'a' + 1;

    for (int i = n - 2, j = 2; i >= 0 && j <= n; i--, j++) {
        suffix[j] = (suffix[j - 1] + 
        (str[i] - 'a' + 1) * power[j - 1]) % mod;
    }
    return suffix;
}

// A Function to find pow (base, exponent) % MOD
// in log (exponent) time
int modPow(int base, int exp) {
    if (exp == 0) return 1;
    if (exp == 1) return base % mod;

    int temp = modPow(base, exp / 2);
    if (exp % 2 == 0) {
        return (temp * temp) % mod;
    } else {
        return (((temp * temp) % mod) * base) % mod;
    }
}

// function to calculate modulo multiplicative inverse
int findMMI(int n) {
    return modPow(n, mod - 2);
}

// function to solve the queries
int solveQuery(string &str, vector<int> &query, 
vector<int> &prefix, vector<int> &suffix, vector<int> &power) {
    int l = query[0], r = query[1];
    int n = str.size();

    // hash value of substring [l, r]
    int hash = (((prefix[r + 1] - prefix[l] + mod) % 
        mod) * findMMI(power[l])) % mod;

    // reverse hash value of substring [l, r]
    int reverseHash = (((suffix[n - l] - suffix[n - r - 1] +
    mod) % mod) * (findMMI(power[n - r - 1]) % mod)) % mod;

    // check if both hashes are equal
    return (hash == reverseHash) ? 1 : 0;
}

// to compute the powers of 101
vector<int> computePowers(int n) {
    vector<int> power(n + 1);
    power[0] = 1;
    for (int i = 1; i <= n; i++) {
        power[i] = (power[i - 1] * 101) % mod;
    }
    return power;
}

// function to check if the substring 
// is a palindrome for each query
vector<int> palindromeQueries(string str, 
    vector<vector<int>>& queries) {
    int n = str.size();
    int q = queries.size();

    // to store the powers of 101
    vector<int> power = computePowers(n);
    
    // compute prefix and suffix hash arrays
    vector<int> prefix = prefixHash(str, power);
    vector<int> suffix = suffixHash(str, power);

    // compute the results
    vector<int> res(q);
    for(int i = 0; i < q; i++) {
        res[i] = solveQuery(str, queries[i], prefix, suffix, power);
    }
    return res;
}

signed main() {
    string str = "abaaabaaaba";
    vector<vector<int>> queries = 
    {{0, 10}, {5, 8}, {2, 5}, {5, 9}};
    vector<int> res = 
    palindromeQueries(str, queries);
    for(auto i: res) {
        cout << i << " ";
    }
    return 0;
}
Java
import java.util.*;

public class GfG {
    static final long mod = 1000000007;

    // function to calculate the prefix hash
    static long[] prefixHash(String str, long[] power) {
        int n = str.length();
        long[] prefix = new long[n + 1];
        prefix[0] = 0;
        prefix[1] = str.charAt(0) - 'a' + 1;

        for (int i = 2; i <= n; i++) {
            prefix[i] = (prefix[i - 1] + 
            (str.charAt(i - 1) - 'a' + 1) * power[i - 1]) % mod;
        }
        return prefix;
    }

    // function to calculate the suffix hash
    static long[] suffixHash(String str, long[] power) {
        int n = str.length();
        long[] suffix = new long[n + 1];
        suffix[0] = 0;
        suffix[1] = str.charAt(n - 1) - 'a' + 1;

        for (int i = n - 2, j = 2; i >= 0 && j <= n; i--, j++) {
            suffix[j] = (suffix[j - 1] + 
            (str.charAt(i) - 'a' + 1) * power[j - 1]) % mod;
        }
        return suffix;
    }

    // A Function to find pow (base, exponent) % MOD
    // in log (exponent) time
    static long modPow(long base, long exp) {
        if (exp == 0) return 1;
        if (exp == 1) return base % mod;

        long temp = modPow(base, exp / 2);
        if (exp % 2 == 0) {
            return (temp * temp) % mod;
        } else {
            return ((temp * temp) % mod * base) % mod;
        }
    }

    // function to calculate modulo multiplicative inverse
    static long findMMI(long n) {
        return modPow(n, mod - 2);
    }

    // function to solve the queries
    static int solveQuery(String str, int[] query, 
    long[] prefix, long[] suffix, long[] power) {
        int l = query[0], r = query[1];
        int n = str.length();

        // hash value of substring [l, r]
        long hash = (((prefix[r + 1] - prefix[l] + mod) 
        % mod) * findMMI(power[l])) % mod;

        // reverse hash value of substring [l, r]
        long reverseHash = (((suffix[n - l] - suffix[n - r - 1] + 
        mod) % mod) * (findMMI(power[n - r - 1]) % mod)) % mod;

        // check if both hashes are equal
        return (hash == reverseHash) ? 1 : 0;
    }

    // to compute the powers of 101
    static long[] computePowers(int n) {
        long[] power = new long[n + 1];
        power[0] = 1;
        for (int i = 1; i <= n; i++) {
            power[i] = (power[i - 1] * 101) % mod;
        }
        return power;
    }

    // function to check if the substring 
    // is a palindrome for each query
    static int[] palindromeQueries(String str, 
    List<int[]> queries) {
        int n = str.length();
        int q = queries.size();

        // to store the powers of 101
        long[] power = computePowers(n);
        
        // compute prefix and suffix hash arrays
        long[] prefix = prefixHash(str, power);
        long[] suffix = suffixHash(str, power);

        // compute the results
        int[] res = new int[q];
        for (int i = 0; i < q; i++) {
            res[i] = solveQuery(str, 
            queries.get(i), prefix, suffix, power);
        }
        return res;
    }

    public static void main(String[] args) {
        String str = "abaaabaaaba";
        List<int[]> queries = new ArrayList<>();
        queries.add(new int[]{0, 10});
        queries.add(new int[]{5, 8});
        queries.add(new int[]{2, 5});
        queries.add(new int[]{5, 9});
        int[] res = palindromeQueries(str, queries);
        for (int i : res) {
            System.out.print(i + " ");
        }
    }
}
Python
mod = 1000000007

# function to calculate the prefix hash
def prefixHash(str, power):
    n = len(str)
    prefix = [0] * (n + 1)
    prefix[0] = 0
    prefix[1] = ord(str[0]) - ord('a') + 1

    for i in range(2, n + 1):
        prefix[i] = (prefix[i - 1] + 
        (ord(str[i - 1]) - ord('a') + 1) * power[i - 1]) % mod
    return prefix

# function to calculate the suffix hash
def suffixHash(str, power):
    n = len(str)
    suffix = [0] * (n + 1)
    suffix[0] = 0
    suffix[1] = ord(str[n - 1]) - ord('a') + 1

    j = 2
    for i in range(n - 2, -1, -1):
        if j <= n:
            suffix[j] = (suffix[j - 1] + 
            (ord(str[i]) - ord('a') + 1) * power[j - 1]) % mod
            j += 1
    return suffix

# A Function to find pow (base, exponent) % MOD
# in log (exponent) time
def modPow(base, exp):
    if exp == 0:
        return 1
    if exp == 1:
        return base % mod

    temp = modPow(base, exp // 2)
    if exp % 2 == 0:
        return (temp * temp) % mod
    else:
        return ((temp * temp) % mod * base) % mod

# function to calculate modulo multiplicative inverse
def findMMI(n):
    return modPow(n, mod - 2)

# function to solve the queries
def solveQuery(str, query, prefix, suffix, power):
    l = query[0]
    r = query[1]
    n = len(str)

    # hash value of substring [l, r]
    hash_val = (((prefix[r + 1] - prefix[l] + mod) % mod) 
    * findMMI(power[l])) % mod

    # reverse hash value of substring [l, r]
    reverseHash = (((suffix[n - l] - suffix[n - r - 1] + mod) 
    % mod) * (findMMI(power[n - r - 1]) % mod)) % mod

    # check if both hashes are equal
    return 1 if (hash_val == reverseHash) else 0

# to compute the powers of 101
def computePowers(n):
    power = [0] * (n + 1)
    power[0] = 1
    for i in range(1, n + 1):
        power[i] = (power[i - 1] * 101) % mod
    return power

# function to check if the substring 
# is a palindrome for each query
def palindromeQueries(str, queries):
    n = len(str)
    q = len(queries)

    # to store the powers of 101
    power = computePowers(n)
    
    # compute prefix and suffix hash arrays
    prefix = prefixHash(str, power)
    suffix = suffixHash(str, power)

    # compute the results
    res = [0] * q
    for i in range(q):
        res[i] = solveQuery(str, queries[i], prefix, suffix, power)
    return res

if __name__ == "__main__":
    str = "abaaabaaaba"
    queries = [[0, 10], [5, 8], [2, 5], [5, 9]]
    res = palindromeQueries(str, queries)
    del str
    print(" ".join(map(str, res)))
C#
using System;
using System.Collections.Generic;
using System.Linq;

public class GfG {
    const long mod = 1000000007;

    // function to calculate the prefix hash
    static long[] prefixHash(string str, long[] power) {
        int n = str.Length;
        long[] prefix = new long[n + 1];
        prefix[0] = 0;
        prefix[1] = str[0] - 'a' + 1;

        for (int i = 2; i <= n; i++) {
            prefix[i] = (prefix[i - 1] + 
            (str[i - 1] - 'a' + 1) * power[i - 1]) % mod;
        }
        return prefix;
    }

    // function to calculate the suffix hash
    static long[] suffixHash(string str, long[] power) {
        int n = str.Length;
        long[] suffix = new long[n + 1];
        suffix[0] = 0;
        suffix[1] = str[n - 1] - 'a' + 1;

        for (int i = n - 2, j = 2; i >= 0 && j <= n; i--, j++) {
            suffix[j] = (suffix[j - 1] + 
            (str[i] - 'a' + 1) * power[j - 1]) % mod;
        }
        return suffix;
    }

    // A Function to find pow (base, exponent) % MOD
    // in log (exponent) time
    static long modPow(long baseVal, long exp) {
        if (exp == 0) return 1;
        if (exp == 1) return baseVal % mod;

        long temp = modPow(baseVal, exp / 2);
        if (exp % 2 == 0) {
            return (temp * temp) % mod;
        } else {
            return ((temp * temp) % mod * baseVal) % mod;
        }
    }

    // function to calculate modulo multiplicative inverse
    static long findMMI(long n) {
        return modPow(n, mod - 2);
    }

    // function to solve the queries
    static int solveQuery(string str, int[] query, 
    long[] prefix, long[] suffix, long[] power) {
        int l = query[0], r = query[1];
        int n = str.Length;

        // hash value of substring [l, r]
        long hash = (((prefix[r + 1] - prefix[l] + mod) 
        % mod) * findMMI(power[l])) % mod;

        // reverse hash value of substring [l, r]
        long reverseHash = (((suffix[n - l] - suffix[n - r - 1] + mod) 
        % mod) * (findMMI(power[n - r - 1]) % mod)) % mod;

        // check if both hashes are equal
        return (hash == reverseHash) ? 1 : 0;
    }

    // to compute the powers of 101
    static long[] computePowers(int n) {
        long[] power = new long[n + 1];
        power[0] = 1;
        for (int i = 1; i <= n; i++) {
            power[i] = (power[i - 1] * 101) % mod;
        }
        return power;
    }

    // function to check if the substring 
    // is a palindrome for each query
    static int[] palindromeQueries(string str, 
                    List<int[]> queries) {
        int n = str.Length;
        int q = queries.Count;

        // to store the powers of 101
        long[] power = computePowers(n);
        
        // compute prefix and suffix hash arrays
        long[] prefix = prefixHash(str, power);
        long[] suffix = suffixHash(str, power);

        // compute the results
        int[] res = new int[q];
        for (int i = 0; i < q; i++) {
            res[i] = solveQuery(str, queries[i], prefix, suffix, power);
        }
        return res;
    }

    public static void Main(string[] args) {
        string str = "abaaabaaaba";
        List<int[]> queries = new List<int[]> {
            new int[] {0, 10},
            new int[] {5, 8},
            new int[] {2, 5},
            new int[] {5, 9}
        };
        int[] res = palindromeQueries(str, queries);
        foreach (int i in res) {
            Console.Write(i + " ");
        }
    }
}
JavaScript
const mod = 1000000007n;

// function to calculate the prefix hash
function prefixHash(str, power) {
    let n = str.length;
    let prefix = new Array(n + 1).fill(0n);
    prefix[0] = 0n;
    prefix[1] = BigInt(str.charCodeAt(0) - 'a'.charCodeAt(0) + 1);
    for (let i = 2; i <= n; i++) {
        prefix[i] = (prefix[i - 1] + (BigInt(str.charCodeAt(i - 1)
        - 'a'.charCodeAt(0) + 1) * power[i - 1])) % mod;
    }
    return prefix;
}

// function to calculate the suffix hash
function suffixHash(str, power) {
    let n = str.length;
    let suffix = new Array(n + 1).fill(0n);
    suffix[0] = 0n;
    suffix[1] = BigInt(str.charCodeAt(n - 1) - 'a'.charCodeAt(0) + 1);
    for (let i = n - 2, j = 2; i >= 0 && j <= n; i--, j++) {
        suffix[j] = (suffix[j - 1] + (BigInt(str.charCodeAt(i) 
        - 'a'.charCodeAt(0) + 1) * power[j - 1])) % mod;
    }
    return suffix;
}

// A Function to find pow (base, exponent) % MOD
// in log (exponent) time
function modPow(base, exp) {
    if (exp === 0n) return 1n;
    if (exp === 1n) return base % mod;
    let temp = modPow(base, exp / 2n);
    if (exp % 2n === 0n) {
        return (temp * temp) % mod;
    } else {
        return ((temp * temp) % mod * base) % mod;
    }
}

// function to calculate modulo multiplicative inverse
function findMMI(n) {
    return modPow(n, mod - 2n);
}

// function to solve the queries
function solveQuery(str, query, prefix, suffix, power) {
    let l = query[0], r = query[1];
    let n = str.length;
    
    // hash value of substring [l, r]
    let hash = (((prefix[r + 1] - prefix[l] + mod) % mod) 
    * findMMI(power[l])) % mod;
    
    // reverse hash value of substring [l, r]
    let reverseHash = (((suffix[n - l] - suffix[n - r - 1] 
    + mod) % mod) * findMMI(power[n - r - 1])) % mod;
    
    // check if both hashes are equal
    return (hash === reverseHash) ? 1 : 0;
}

// to compute the powers of 101
function computePowers(n) {
    let power = new Array(n + 1).fill(0n);
    power[0] = 1n;
    for (let i = 1; i <= n; i++) {
        power[i] = (power[i - 1] * 101n) % mod;
    }
    return power;
}

// function to check if the substring 
// is a palindrome for each query
function palindromeQueries(str, queries) {
    let n = str.length;
    let q = queries.length;
    
    // to store the powers of 101
    let power = computePowers(n);
    
    // compute prefix and suffix hash arrays
    let prefix = prefixHash(str, power);
    let suffix = suffixHash(str, power);
    
    // compute the results
    let res = new Array(q);
    for (let i = 0; i < q; i++) {
        res[i] = solveQuery(str, queries[i], prefix, suffix, power);
    }
    return res;
}

function main() {
    let str = "abaaabaaaba";
    let queries = [[0, 10], [5, 8], [2, 5], [5, 9]];
    let res = palindromeQueries(str, queries);
    console.log(res.join(" "));
}

main();

Output
1 0 0 1 


Next Article

Similar Reads