Exercises — Boyer-Moore — bad character, good suffix heuristics
3.8.5 · D4· Coding › String Algorithms › Boyer-Moore — bad character, good suffix heuristics
Reminders jo tum constantly use karoge (sab parent se hain):
Puri note mein indices 0-based hain: pehla character hai, aakhri.
Neeche di gayi picture har problem ke liye tumhara mental model hai. Isko baar baar dekhte rehna.

Level 1 — Recognition
L1.1 () ke liye, har us letter ke liye likho jo aata hai, aur batao.
Recall Solution
Pattern ko index karo: . woh rightmost index hai jahan appear karta hai.
- (sirf index 0 par).
- — E 1, 2, 5 par aata hai; rightmost hai 5.
- .
- .
- — X aata hi nahi, isliye hum "not present" sentinel return karte hain.
L1.2 Boyer-Moore mein, pattern ka kaun sa end hum pehle compare karte hain, aur kyun?
Recall Solution
Hum pehle rightmost character ko text se compare karte hain, phir left ki taraf move karte hain. Reason: right ke paas mismatch humein batata hai ki ek poora matched suffix already line up ho chuka tha. Wahi matched suffix exactly hai jo good-suffix rule exploit karta hai, aur mismatching text character woh hai jo bad-character rule exploit karta hai. Agar hum left-to-right compare karte (naive matching ki tarah) toh hum koi suffix nahi seekh paate, aur bade skips impossible ho jaate.
L1.3 Ek string ka "border" kya hota hai, ek sentence mein?
Recall Solution
Ek border ek proper substring hai (poori string nahi) jo ek saath prefix bhi ho aur suffix bhi. Example: ANANA mein string ANA ek border hai (yeh pehle 3 chars bhi hai aur aakhri 3 chars bhi). Yeh Borders and Prefix Function se connect hota hai.
Level 2 — Application
L2.1 (). Mismatch par hota hai (toh ) aur wahan text character hai. compute karo.
Recall Solution
ABCAB mein : B indices 1 aur 4 par aata hai, isliye .
.
Raw formula ne diya (matlab backward shift hota!), isliye clamp humein bachata hai. Yahan bad-character rule weak hai; real run mein good-suffix rule actual jump provide karega.
L2.2 Wahi , mismatch par (last char compare karte waqt) text char ke saath. compute karo.
Recall Solution
(Z absent hai). . Kyunki Z mein kahin nahi hai, hum poore pattern ko us text position ke aage slide karte hain — poori pattern length ka ek jump. Yahi BM ka sublinear magic hai.
L2.3 (). Mismatch par text char ke saath. compute karo.
Recall Solution
Index: . . Lekin mismatch khud par hai — bad char bilkul usi index se align ho raha hai jahan mismatch hua. . Clamp phir fire karta hai: matlab "move hi mat karo," jo illegal hai. Hum lete hain.
Level 3 — Analysis
L3.1 () ke liye array compute karo, jahan woh length hai — ke index par khatam hone wale longest suffix ki — jo poore ka bhi suffix ho.
Recall Solution
Index: at . Whole-pattern suffix right to left padhne par G A G A G A C G aata hai.
- by convention (poori string khud apna suffix hai).
- : index 6 par khatam hone wala suffix
...Ahai; whole-PGse khatam hota hai.A≠G→ . - : index 5 par
Ghai; compare karoG(P[5]) vsG(P[7]) match;A(P[4]) vsA(P[6]) match;G(P[3]) vsG(P[5]) match;A(P[2]) vsA(P[4]) match; P[1]=Cvs P[3]=Gstop. Indices 5,4,3,2 par walk → . - : index 4 par
Avs P[7]G→ . - :
GvsGmatch; P[2]Avs P[6]Amatch; P[1]Cvs P[5]Gstop → . - :
AvsG→ . - :
CvsG→ . - :
GvsGmatch, left mein aur chars nahi → . Result: .
L3.2 (). Good suffix AN (length 2) match hua, mismatch index par (char ). AN ke do aur copies hain, indices aur par. Explain karo kyun hum ek copy ko Case-1 candidate ke roop mein reject karte hain, aur hum actually kaun si copy align karte hain.
Recall Solution
Index: at . Good suffix hai ; mismatch par, .
Case 1 require karta hai ki good suffix ki kisi internal copy ke just pehle wala character mismatch char se alag ho — warna us copy par slide karne se same relative position par same M aa jaayega aur identical mismatch repeat hoga (zero progress).
- wali copy ko Case-1 candidate ke roop mein reject karo: iske koi preceding character nahi (yeh ki bilkul shuruat mein hai). Case 1 ko ek genuinely internal copy chahiye jiske aage ek real preceding char ho test karne ke liye, isliye yeh leading copy Case-1 hit nahi hai — yeh sirf Case-2 / prefix fallback ke through contribute karta hai.
- wali copy ko accept karo: iska preceding char hai, aur ✓. Yeh ek valid Case-1 copy hai.
Toh hum wali copy ko text ke
ANke neeche align karte hain. Shift waliANko wahan move karta hai jahan waliANhai: . (Agar dono inner copiesMse preceded hoti, toh hum Case 2 par jaate aur ka prefix use karte.)
L3.3 lena hamesha safe kyun hai (koi real occurrence skip nahi hota)?
Recall Solution
Har rule independently ek guaranteed lower-bound jump ke roop mein derive kiya gaya hai: "skipped region mein koi valid match start nahi ho sakta." Bad-character rule yeh mismatching text char se prove karta hai; good-suffix rule yeh matched suffix se prove karta hai. Agar jump safe hai aur jump safe hai, toh se strictly neeche ka har alignment kam se kam ek proof se rule out hota hai — isliye bhi safe hai. Bada lena matlab hum sirf us proof par trust karte hain jo zyada door tak pahunchta hai.
Level 4 — Synthesis
L4.1 (). Sab letters ke liye compute karo, phir compute karo jab hum kisi par align karein, right-to-left compare karein, aur pehla mismatch par text char ke saath ho.
Recall Solution
Index: at . . Mismatch , , mein absent hai: . Hum poori pattern width jump karte hain, sirf ek text character padhke. Yahi is alignment par BM ka sublinear behaviour hai.
L4.2 Wahi . Ab maano kisi alignment par match hua lekin mismatch hua, yaani , text char ke saath. Dono heuristics ke shifts aur final BM shift compute karo. (Good suffix ke liye, matched suffix sirf C hai; mein pehle wale Cs indices 0,1,7 par hain.)
Recall Solution
Bad character: , . .
Good suffix: matched suffix hai (length 1), yaani toh hum chahte hain. Humein mein C ki ek aisi pehle wali copy chahiye jiska preceding char mismatch char se alag ho, taaki text ke trailing C ke neeche align kiya ja sake.
- Index 1 par
C: preceding char ✓. kiCko us text position par le jaao jo currently ke target par hai; shift jo kiCko us slot par laata hai jahan kiChai woh hai . - (
Cat index 0 ka koi preceding char nahi; index 1 sabse paas wali valid inner copy hai, jo sabse chhota safe good-suffix jump = deti hai.) . Final: . Yahi exactly woh scenario hai jiske baare mein parent note warn karta hai: bad char akele feeble deta hai; good suffix usse se rescue karta hai.
L4.3 BM ka trace karo ( of both heuristics use karte hue) (text length ), () par. Har try kiya gaya alignment aur har reported match list karo. Mismatches par good-suffix rule kya contribute karta hai woh bhi dikhao.
Recall Solution
, indices . , baaki . Yaad rakho (text length), toh last valid alignment par hai.
Good-suffix array facts jo chahiye. AABA ka longest proper border A hai (prefix A = suffix A), isliye full-match shift hai .
Neeche ke mismatches mein mismatch hamesha par hai (chars B vs non-B), isliye matched suffix hai (length 1) aur humein chahiye. mein pehle wali A kahin milti hai jiska preceding char se alag ho? Index 0 par A ke aage kuch nahi (leading hai), index 3 par A wahi matched wali hai; Case 1 ke liye nearest usable earlier A index 0 via prefix/Case-2 route hai. Calculate karne par AABA ke liye aata hai. Toh in mismatches par .
Step through karo, hamesha rakhte hue:
- : vs
AABAcompare karo → full match. Report . Shift . - : . vs ✓; vs ✗ at , absent. ; . Final . (Yahan bad char jeetta hai, lekin good suffix ne independently 2 ka jump justify kiya.)
- : . ✓; vs ✗ at , absent. , , final .
- : → full match. Report . Shift .
- : → full match. Report . Shift . Ruko. Matches par. Alignments try kiye: — paanch, naive ke ke muqable mein.
L4.4 () ke liye two-pass procedure aur L3.1 ki array use karke poora good-suffix array banao. Har pass dikhao.
Recall Solution
L3.1 se: , .
Init: (length ).
Pass A (Case 2, prefix = suffix). Hum woh indices dhundhte hain jahan ho (yaani poore pattern ka prefix par khatam hota hai). Check karo: ✓ (prefix G). Koi aur satisfy nahi karta (, , etc.). Toh sirf ek surviving prefix hai length ka, start index — sabse chota start hai . Har ke liye jo abhi kisi strong rule se set nahi hua, fill karo . Concretely yeh un high- positions pe Case-2 default set karta hai jahan prefix reach karta hai; .
Pass B (Case 1, internal reoccurrence). ke liye, set karo aur , increasing sweep karte hue taaki rightmost copies tightest shift dein:
- : , .
- : , .
- : , .
- ( wale indices dete hain, jo ki taraf harmlessly overwrite hote hain.) Result (ek standard convention): with Case-2 fills of jo untouched high positions par apply hote hain. Jo do shifts tum sabse zyada use karte ho woh hain (full-match jump) aur Case-1 entries . Key competency: ab tum se koi bhi derive kar sakte ho, guess karne ki zaroorat nahi.
Level 5 — Mastery
L5.1 Woh classic worst case construct karo jahan basic Boyer-Moore tak degrade ho jaata hai, aur explain karo kyun dono heuristics help nahi karte. Phir batao isko fix kya karta hai.
Recall Solution
Lo () aur ( copies of A).
Har alignment par, right-to-left scan tak sab match karta hai (koi mismatch andar nahi), toh hum comparisons per alignment karte hain. Approximately alignments hain. Total .
Kyun heuristics nahi bachate: good-suffix full-match shift hai (AAAA ka longest proper border AAA hai, length 3). Bad-character bhi chhote shifts deta hai kyunki har char A hai. Toh hum ek ek karke aage creep karte rehte hain aur matched characters ko baar baar re-read karte hain.
Fix: Galil Rule yaad rakhta hai ki previous match kitna aage pahuncha tha aur us region ko re-compare karna skip karta hai, guaranteed restore karta hai.
L5.2 Tumhare paas ek huge DNA text () aur ek lamba DNA pattern hai. Kya tum expect karoge ki Boyer-Moore ka sublinear best case strongly kick in karega? English text search se ya connections list ke kisi alternative algorithm se compare karo.
Recall Solution
BM ki sublinear speed alphabet size ke saath badhti hai: bada alphabet mismatching text char ko mein often absent banata hai, jo full-length bad-character jumps trigger karta hai (jaise L2.2 aur L4.1 mein). DNA mein sirf 4 symbols hain, isliye "absent character" rare hai — almost har text char mein bhi hota hai, toh bad-character jumps usually chhote hote hain aur good-suffix rule end up mein zyada useful kaam karta hai. BM DNA par bilkul usable hai, lekin uske skips chhote hote hain aur yeh English (26+ letters) ya arbitrary byte data (256 symbols) ke comparison mein kam dramatically sublinear hai, jahan bade absent-char jumps common hain. Connections list ke alternatives: chhote alphabets ke liye ya jab tumhe hard linear guarantee chahiye, prefer karo Knuth-Morris-Pratt (KMP) (strict , Borders and Prefix Function ke prefix function par built); Z-Algorithm same linear guarantee deta hai bahut clean construction ke saath. Agar tumhe ek saath bahut saare patterns search karne hain, toh Aho-Corasick BM ko repeatedly run karne se behtar hai, aur Rabin-Karp attractive hai jab hashing / multiple-pattern averaging help kare. Short mein: BM tab shine karta hai jab alphabet bada ho aur pattern moderately lamba ho; chhote-alphabet DNA par linear-time competitors aksar zyada safe default hote hain.
L5.3 Prove karo ki bad-character shift koi valid occurrence skip nahi karta jab ho.
Recall Solution
Maano mismatch pattern index par hai, aur offending text char hai , with ( mein ka rightmost index hai, se left mein). Agar kisi shift par match kare, toh absolute position par text character (jo hai) kisi aise pattern index ke saath align hona chahiye jo actually hold karta ho. Aisa largest index hai. ko position ke neeche align karne ke liye chahiye. Koi bhi jahan ho, wahan ek non- pattern index us ke upar aayega, jo immediate mismatch force karega — toh woh alignments impossible hain. Isliye se jump karna sirf provably-empty alignments ko skip karta hai. sirf forward progress guarantee karta hai jab formula non-positive ho.
L5.4 Ek pattern aur mismatch do jahan good-suffix shift Case 2 (border fallback) se aaye, Case 1 se nahi, aur woh shift compute karo. Explain karo kyun Case 1 fire nahi ho sakta.
Recall Solution
Lo (), indices = A B A B A. Maano scan ne suffix (length 3) match kiya aur par mismatch hua, .
Kyun Case 1 fire nahi ho sakta: humein ABA ki ek aur full copy ke andar chahiye jo strictly index 4 se pehle khatam ho, aur jiska preceding char se alag ho. ABA ki jedhi aur occurrence hai, lekin yeh index 0 se start hoti hai jiske aage koi preceding character nahi hai, isliye yeh valid strictly-internal Case-1 copy nahi hai. Good suffix ki koi full inner copy qualify nahi karti.
Case 2 (border fallback): hum instead ka longest prefix dhundhte hain jo ke suffix ke barabar ho. ABA ke suffixes hain A, BA, ABA. Inme se kaun ABABA ka prefix hai? A ✓, ABA ✓ (prefix ABA), BA ✗. Longest hai ABA, length 3. Shift .
Yeh pattern ke leading ABA ko us text region ke neeche land karta hai jo ABA se match hua tha, bacha hua sirf ek self-consistent placement. Case 2 yahan bhool jaana matlab tum over-shift karo aur ek real occurrence miss kar do.
Recall Self-check clozes
Bad-character shift jab mein absent ho aur mismatch index par ho ::: (yaani ), poora pattern aage slide ho jaata hai.
Full-match shift ke liye ::: .
Case-2 good-suffix shift ABABA ke liye jab good suffix ABA ho ::: ( ka longest prefix jo good suffix ke suffix ke barabar ho woh ABA hai).
What restores worst case ::: the Galil Rule.
Kyun BM DNA par kam sublinear hai ::: sirf 4 symbols hain, isliye absent-character full jumps rare hain.