Level 2 — RecallString Algorithms

String Algorithms

30 minutes40 marksprintable — key stays hidden on paper

Chapter: 3.8 String Algorithms Difficulty Level: 2 (Recall — definitions, standard problems, short derivations) Time Limit: 30 minutes Total Marks: 40


Instructions: Answer all questions. Show working where derivations are required. Use ...... notation for indices and complexities.


Q1. State the worst-case time complexity of naive pattern matching for a text of length nn and pattern of length mm. Give one example of a text–pattern pair that forces this worst case. (3 marks)

Q2. Compute the KMP failure function (longest proper prefix that is also a suffix) array π\pi for the pattern: P="ababaca"P = \texttt{"ababaca"} Show the value of π[i]\pi[i] for each index i=06i = 0 \dots 6. (5 marks)

Q3. Explain in 2–3 sentences why KMP achieves O(n+m)O(n+m) time. Refer to how the failure function avoids re-examining text characters. (4 marks)

Q4. In Rabin–Karp, the rolling hash for a window is updated in O(1)O(1). Given base bb, window length mm, and current hash hh for substring s[ii+m1]s[i \dots i+m-1], write the formula to obtain the hash of s[i+1i+m]s[i+1 \dots i+m] (modulo a prime qq). Define each term. (5 marks)

Q5. Construct the Z-array for the string: S="aabaab"S = \texttt{"aabaab"} Give Z[i]Z[i] for i=05i = 0 \dots 5 (using the convention Z[0]=0Z[0]=0 or the full length; state your convention). (5 marks)

Q6. Define the bad character heuristic in the Boyer–Moore algorithm. For pattern P="BANANA"P = \texttt{"BANANA"}, state how far to shift if a mismatch occurs at a text character 'X' (a character not in PP). (4 marks)

Q7. Briefly describe what an Aho–Corasick automaton adds to a trie of patterns, and state its total search complexity for text length nn, total pattern length mm, and zz matches. (4 marks)

Q8. Given the string S="banana"S = \texttt{"banana"}, list all suffixes and give the suffix array (the array of starting indices sorted lexicographically). (5 marks)

Q9. State the purpose of Manacher's algorithm and its time complexity. What preprocessing trick (character insertion) allows it to handle even-length palindromes uniformly? (3 marks)

Q10. One-line each: name the data structure or algorithm best suited for (a) searching many patterns simultaneously, (b) finding the longest palindromic substring in linear time. (2 marks)


End of Paper

Answer keyMark scheme & solutions

Q1. (3 marks)

  • Worst case: O(nm)O(nm). (1)
  • Example: text ="aaaa...a"=\texttt{"aaaa...a"} (nn a's), pattern ="aa...ab"=\texttt{"aa...ab"} (m1m-1 a's then b). (1)
  • Why: at each of nm+1\sim n-m+1 alignments the algorithm matches m1m-1 characters before failing on the last, giving Θ((nm+1)m)=Θ(nm)\Theta((n-m+1)\cdot m)=\Theta(nm). (1)

Q2. (5 marks) Pattern P=ababacaP=\texttt{ababaca}, indices 0–6.

i char π[i]\pi[i]
0 a 0
1 b 0
2 a 1
3 b 2
4 a 3
5 c 0
6 a 1

Array: π=[0,0,1,2,3,0,1]\pi = [0,0,1,2,3,0,1]. (1 mark per correct value cluster; award 5 for full array, deduct 1 per wrong entry) Why: π[i]\pi[i] = length of longest proper prefix of P[0..i]P[0..i] that is also a suffix. E.g. at i=4i=4 (ababa), aba (len 3) matches; at i=5i=5 (ababac), c breaks all borders → 0.

Q3. (4 marks)

  • KMP never moves the text pointer backward. (1)
  • On a mismatch, the failure function tells us the largest prefix already matched, so the pattern shifts without re-comparing those characters. (1)
  • Each text character is examined a constant amortized number of times; the potential/counter argument bounds comparisons by O(n)O(n). (1)
  • Failure function precomputation is O(m)O(m), so total O(n+m)O(n+m). (1)

Q4. (5 marks) h=(b(hs[i]bm1)+s[i+m])modqh' = \big(b\cdot(h - s[i]\cdot b^{m-1}) + s[i+m]\big) \bmod q

  • hh = current hash of window s[i..i+m1]s[i..i+m-1]. (1)
  • s[i]bm1s[i]\cdot b^{m-1} = contribution of the leaving (leftmost) character; subtract it. (1)
  • multiply by bb = shift remaining characters up one power. (1)
  • +s[i+m]+\,s[i+m] = add the new incoming character. (1)
  • all reduced mod prime qq; bm1modqb^{m-1}\bmod q precomputed → O(1)O(1) update. (1)

Q5. (5 marks) Convention: Z[0]=0Z[0]=0 (undefined/length by convention); Z[i]Z[i] = length of longest substring starting at ii matching a prefix of SS. S=aabaabS=\texttt{aabaab}.

i suffix Z[i]Z[i]
0 aabaab 0 (or 6)
1 abaab 1
2 baab 0
3 aab 3
4 ab 1
5 b 0

Z=[0,1,0,3,1,0]Z = [0,1,0,3,1,0]. (deduct 1 per wrong entry) Why: at i=3i=3, aab matches prefix aab fully (length 3). At i=1i=1, only a matches prefix a.

Q6. (4 marks)

  • Bad character heuristic: on a mismatch, align the pattern so that the last occurrence (in PP) of the mismatched text character lines up with it; if the character does not occur in PP, shift the pattern entirely past that position. (2)
  • For P=BANANAP=\texttt{BANANA} and mismatch on 'X' (not in PP): shift so pattern moves past the mismatch — shift by m=6m=6 (full pattern length, relative to comparison start). (2)

Q7. (4 marks)

  • Aho–Corasick augments the trie with failure links (like KMP's failure function generalized to a trie): a failure link points to the node representing the longest proper suffix of the current string that is also a prefix of some pattern. (2)
  • Output links collect all patterns ending at each node. (0.5)
  • Search complexity: O(n+m+z)O(n + m + z) where zz = number of matches. (1.5)

Q8. (5 marks) S=bananaS=\texttt{banana} (indices 0–5). Suffixes: 0:banana, 1:anana, 2:nana, 3:ana, 4:na, 5:a. Sorted lexicographically: a(5), ana(3), anana(1), banana(0), na(4), nana(2). Suffix array = [5,3,1,0,4,2][5, 3, 1, 0, 4, 2]. (2 for correct suffix list, 3 for correct SA)

Q9. (3 marks)

  • Purpose: find longest palindromic substring / all palindromic radii in linear time. (1)
  • Complexity: O(n)O(n). (1)
  • Trick: insert a separator (e.g. #) between every character and at the ends, converting the string into odd length so even- and odd-length palindromes are treated uniformly. (1)

Q10. (2 marks)

  • (a) Aho–Corasick automaton. (1)
  • (b) Manacher's algorithm. (1)

[
  {"claim":"KMP failure function of 'ababaca' is [0,0,1,2,3,0,1]","code":"def pi(P):\n    n=len(P); f=[0]*n; k=0\n    for i in range(1,n):\n        while k>0 and P[i]!=P[k]:\n            k=f[k-1]\n        if P[i]==P[k]:\n            k+=1\n        f[i]=k\n    return f\nresult = pi('ababaca')==[0,0,1,2,3,0,1]"},
  {"claim":"Z-array of 'aabaab' is [0,1,0,3,1,0] (Z[0]=0 convention)","code":"def zarr(s):\n    n=len(s); Z=[0]*n; l=r=0\n    for i in range(1,n):\n        if i<r: Z[i]=min(r-i,Z[i-l])\n        while i+Z[i]<n and s[Z[i]]==s[i+Z[i]]:\n            Z[i]+=1\n        if i+Z[i]>r: l,r=i,i+Z[i]\n    return Z\nresult = zarr('aabaab')==[0,1,0,3,1,0]"},
  {"claim":"Suffix array of 'banana' is [5,3,1,0,4,2]","code":"s='banana'\nsa=sorted(range(len(s)), key=lambda i:s[i:])\nresult = sa==[5,3,1,0,4,2]"},
  {"claim":"Rabin-Karp rolling hash update matches recomputation","code":"b=256; q=1000000007; s=[ord(c) for c in 'abcde']; m=3\nh=0\nfor k in range(m): h=(h*b+s[k])%q\nbm1=pow(b,m-1,q)\nhnext=(b*((h - s[0]*bm1)%q)+s[m])%q\nrecomp=0\nfor k in range(1,1+m): recomp=(recomp*b+s[k])%q\nresult = hnext%q==recomp%q"}
]