Palindrome Substring Queries
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.
Table of Content
[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.
#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;
}
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 + " ");
}
}
}
# 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)))
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));
}
}
// 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 usingreverse_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 = 108242031437886501387Now 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 M3) Mixture of addition and multiplication
(a * x + b * y + c) % M = ( (a * x) % M +(b * y) % M+ c % M ) % M4) 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] = 0prefix[i] = str[0] + str[1] * 101 + str[2] * 101 ^ 2 + ... + str[i - 1] * 101 ^ {i - 1} - Using prefix hashing, the hash value of a substring
str[L:R]
can be found as:hash(L, R) = prefix[R + 1] - prefix[L] - Similar to this, we compute the suffix hash as:
suffix[0] = 0suffix[i] = str[n - 1] + str[n - 2] * 101 + str[n - 3] * 101 ^ 2 + ... + str[n - i] * 101 ^ {i - 1} - Using suffix hashing, the reverse hash of a substring str[L:R] can be found as:
reverseHash(L, R) = suffix[n - L] - suffix[n - R - 1] - A substring str[L:R] is a palindrome if:
prefix[R + 1] - prefix[L] / 101 ^ L = suffix[n - L] - suffix[n - R - 1] / 101 ^ {n - R - 1} - 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.
#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;
}
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 + " ");
}
}
}
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)))
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 + " ");
}
}
}
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