给定两个字符串A , B以及一些由整数i组成的查询,任务是检查A的子字符串是否从索引i开始并以索引i + length(B)– 1结束,是否等于B。如果相等,则打印“是”,否则打印“否” 。请注意, i + length(B)将始终小于length(A) 。
例子:
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
一种简单的方法将是字符串逐个的每个查询,这将花费O(长度(B))的时间来回答每个查询进行比较。
高效的方法:我们将使用滚动哈希算法优化查询处理。
首先,我们将找到字符串B的哈希值。然后,使用滚动哈希技术,将对字符串A进行预处理。
假设我们创建了一个数组hash_A。然后,该数组的第i个元素将存储。
((a[0] – 97) + (a[1] – 97) * d + (a[2] – 97) * d2 + ….. + (a[i] – 97) * di) % mod
where d is the multiplier in rolling-hash.
我们将使用它来查找A的子字符串的哈希。
从i开始的A子字符串的哈希可以找到(hash_a [i + len_b – 1] – hash_a [i – 1])/ d i或更具体地
((hash_a[i + len_b – 1] – hash_a[i – 1] + 2 * mod) * mi(di)) % mod
因此,使用它我们可以回答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)