Program to count number of similar substrings for each query in Python


Suppose we have two strings s and a set of query Q. Where Q[i] contains pair (l, r), for each substring of s from l to r, we have to find number of substrings s from x to y where they are similar. Two strings s and t are similar if they follow these rules −

  • They are of same length

  • For each pair of indices (i, j), if s[i] is same as s[j], then it must satisfy t[i] = t[j], and similarly if s[i] is not same as s[j], then t[i] and t[j] must be different.

So, if the input is like s = "hjhhbcbk" Q = [(1,2), (2,4)], then the output will be [6, 1] because

  • For first query the similar substrings are "hj", "jh", "hb", "bc", "cb" and "bk".
  • For first query the similar substring is "jhh"

To solve this, we will follow these steps −

  • fp := a new list
  • Define a function calc_fingerprint() . This will take s
  • dict := a new dictionary, and initially insert key-value pair (s[0], 0)
  • fp := "0"
  • j := 1
  • for i in range 1 to size of s - 1, do
    • if s[i] is not present in dict, then
      • dict[s[i]] := j
      • j = j+1
    • fp := fp + string representation of dict[s[i]]
  • return integer form of fp
  • From the main method, do the following −
  • if size of s > 10, then
    • for i in range 0 to size of s - 10, do
      • x := calc_fingerprint(s[from index i to i+9])
      • insert x at the end of fp
  • ret := a new list
  • for i in range 0 to size of Q - 1, do
    • (a, b) := Q[i]
    • s1 := substring of s from index a-1 to b-1
    • k := 0
    • for i in range 0 to size of s - (b-a), do
      • if b-a > 9 and fp[a-1] is not same as fp[i], then
        • go for next iteration
      • dict := a new empty map
      • s2 := substring of s from index i to i+(b-a)
      • for i in range 0 to b-a, do
        • if s2[i] is not in dict, then
          • if s1[i] is in values of dict, then
            • come out from loop
          • dict[s2[i]] := s1[i]
        • if dict[s2[i]] is not same as s1[i], then
          • come out from loop
      • otherwise,
        • k := k + 1
    • insert k at the end of ret
  • return ret

Example

Let us see the following implementation to get better understanding −

fp = []

def calc_fingerprint(s):
   dict = {s[0]: 0}
   fp = "0"
   j = 1
   for i in range(1, len(s)):
      if s[i] not in dict:
         dict[s[i]], j = j, j+1
      fp += str(dict[s[i]])
   return int(fp)

def solve(s, Q):
   if len(s) > 10:
      for i in range(0, len(s)-10):
         fp.append(calc_fingerprint(s[i: i+10]))

   ret = []
   for i in range(len(Q)):
      a, b = Q[i]
      s1 = s[a-1:b]
      k = 0
      for i in range(len(s)-(b-a)):
         if b-a > 9 and fp[a-1] != fp[i]:
            continue
         dict = {}
         s2 = s[i:i+(b-a)+1]
         for i in range(b-a+1):
            if s2[i] not in dict:
               if s1[i] in dict.values(): break
               dict[s2[i]] = s1[i]
            if dict[s2[i]] != s1[i]: break
         else:
            k += 1
      ret.append(k)

   return ret

s = "hjhhbcbk"
Q = [(1,2), (2,4)]
print(solve(s, Q))

Input

"hjhhbcbk", [(1,2), (2,4)]

Output

[6, 1]

Updated on: 11-Oct-2021

269 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements