Bird
Raised Fist0
DSA Cprogramming

KMP Pattern Matching Algorithm in DSA C

Choose your learning style10 modes available
Mental Model
KMP finds a pattern in text by remembering where to restart after a mismatch, avoiding repeated checks.
Analogy: Imagine searching a word in a book and using a bookmark to jump back to the right page instead of starting over from the beginning.
Text:  A B C D A B C D A B C D
Pattern:       A B C D
Prefix Table: [0,0,0,0]
Dry Run Walkthrough
Input: text: "ABABDABACDABABCABAB", pattern: "ABABCABAB"
Goal: Find all starting indices where the pattern appears in the text using KMP.
Step 1: Build prefix table for pattern
pattern: A B A B C A B A B
prefix table: [0,0,1,2,0,1,2,3,4]
Why: Prefix table tells where to restart pattern matching after mismatch
Step 2: Start matching pattern with text at index 0
text: [A] B A B D A B A C D A B A B C A B A B
pattern: [A] B A B C A B A B
Why: First characters match, continue checking next
Step 3: Mismatch at text index 4 and pattern index 4
text: A B A B [D] A B A C D A B A B C A B A B
pattern: A B A B [C] A B A B
restart pattern index to prefix_table[3]=2
Why: Mismatch found, use prefix table to avoid rechecking from start
Step 4: Continue matching from pattern index 2 and text index 4
text: A B A B D [A] B A C D A B A B C A B A B
pattern: A B [A] B C A B A B
Why: Restart pattern matching from index 2 to save time
Step 5: Find full pattern match starting at text index 10
text: A B A B D A B A C D [A B A B C A B A B]
pattern: A B A B C A B A B
Why: Pattern fully matched, record index 10
Result:
Match found at indices: 10
Annotated Code
DSA C
#include <stdio.h>
#include <string.h>

void buildPrefixTable(char* pattern, int* prefix, int m) {
    int len = 0; // length of previous longest prefix suffix
    prefix[0] = 0; // first value always 0
    int i = 1;
    while (i < m) {
        if (pattern[i] == pattern[len]) {
            len++;
            prefix[i] = len;
            i++;
        } else {
            if (len != 0) {
                len = prefix[len - 1]; // fallback in prefix
            } else {
                prefix[i] = 0;
                i++;
            }
        }
    }
}

void KMPSearch(char* text, char* pattern) {
    int n = strlen(text);
    int m = strlen(pattern);
    int prefix[m];
    buildPrefixTable(pattern, prefix, m);

    int i = 0; // index for text
    int j = 0; // index for pattern
    printf("Match found at indices: ");
    int found = 0;
    while (i < n) {
        if (pattern[j] == text[i]) {
            i++;
            j++;
        }
        if (j == m) {
            printf("%d ", i - j); // pattern found
            j = prefix[j - 1]; // continue searching
            found = 1;
        } else if (i < n && pattern[j] != text[i]) {
            if (j != 0) {
                j = prefix[j - 1]; // fallback in pattern
            } else {
                i++;
            }
        }
    }
    if (!found) {
        printf("-1");
    }
    printf("\n");
}

int main() {
    char text[] = "ABABDABACDABABCABAB";
    char pattern[] = "ABABCABAB";
    KMPSearch(text, pattern);
    return 0;
}
while (i < m) { if (pattern[i] == pattern[len]) { len++; prefix[i] = len; i++; } else { if (len != 0) { len = prefix[len - 1]; } else { prefix[i] = 0; i++; } } }
build prefix table to know fallback positions on mismatch
while (i < n) { if (pattern[j] == text[i]) { i++; j++; } if (j == m) { printf("%d ", i - j); j = prefix[j - 1]; } else if (i < n && pattern[j] != text[i]) { if (j != 0) { j = prefix[j - 1]; } else { i++; } } }
match pattern in text using prefix table to skip unnecessary checks
OutputSuccess
Match found at indices: 10
Complexity Analysis
Time: O(n + m) because we build prefix table in O(m) and scan text in O(n) without backtracking
Space: O(m) for prefix table storing fallback positions for pattern
vs Alternative: Naive search is O(n*m) because it restarts from next text index on mismatch; KMP avoids this by using prefix table
Edge Cases
Empty pattern
No matches found, prints -1
DSA C
int m = strlen(pattern);
Pattern longer than text
No matches found, prints -1
DSA C
while (i < n) { ... }
Pattern equals text
Match found at index 0
DSA C
if (j == m) { printf("%d ", i - j); j = prefix[j - 1]; }
When to Use This Pattern
When you need to find a pattern inside a text efficiently and avoid repeated comparisons, use KMP because it remembers where to restart after mismatches.
Common Mistakes
Mistake: Not building the prefix table correctly, causing wrong fallback positions.
Fix: Carefully update prefix table using previous longest prefix suffix length and fallback when mismatch occurs.
Mistake: Not updating pattern index j correctly after a full match.
Fix: After a full match, reset j to prefix[j-1] to continue searching for overlapping matches.
Summary
KMP finds all occurrences of a pattern in a text efficiently by using a prefix table to skip unnecessary comparisons.
Use KMP when you want fast pattern searching without restarting from scratch after mismatches.
The key insight is the prefix table that tells where to restart matching in the pattern after a mismatch.

Practice

(1/5)
1. What is the main purpose of the KMP (Knuth-Morris-Pratt) algorithm in pattern matching?
easy
A. To efficiently find occurrences of a pattern in a text without rechecking characters
B. To sort the characters of the pattern alphabetically
C. To reverse the text before searching
D. To count the total number of characters in the text

Solution

  1. Step 1: Understand KMP's goal

    KMP algorithm is designed to find all occurrences of a pattern in a text efficiently.
  2. Step 2: Identify how KMP works

    It avoids rechecking characters by using a prefix table to skip unnecessary comparisons.
  3. Final Answer:

    To efficiently find occurrences of a pattern in a text without rechecking characters -> Option A
  4. Quick Check:

    KMP = Efficient pattern search [OK]
Hint: KMP skips repeated checks using prefix info [OK]
Common Mistakes:
  • Thinking KMP sorts or reverses strings
  • Confusing KMP with simple substring search
  • Assuming KMP counts characters only
2. Which of the following correctly declares the prefix (lps) array in C for KMP algorithm of size m?
easy
A. int *lps = malloc(m * sizeof(int));
B. int lps = new int[m];
C. int lps[m];
D. int lps[] = {m};

Solution

  1. Step 1: Understand array declaration in C

    Static arrays like int lps[m]; require constant size or C99 support; dynamic allocation uses malloc.
  2. Step 2: Identify correct dynamic allocation

    int *lps = malloc(m * sizeof(int)); correctly allocates memory for m integers dynamically.
  3. Final Answer:

    int *lps = malloc(m * sizeof(int)); -> Option A
  4. Quick Check:

    Dynamic array = malloc usage [OK]
Hint: Use malloc for dynamic arrays in C [OK]
Common Mistakes:
  • Using Java-style array allocation in C
  • Incorrect static array size syntax
  • Misusing array initialization syntax
3. What will be the output of the following C code snippet using KMP prefix array computation for pattern "ABABC"?
int main() {
    char pattern[] = "ABABC";
    int m = 5, i = 1, len = 0;
    int lps[5] = {0};
    while (i < m) {
        if (pattern[i] == pattern[len]) {
            len++;
            lps[i] = len;
            i++;
        } else {
            if (len != 0) {
                len = lps[len - 1];
            } else {
                lps[i] = 0;
                i++;
            }
        }
    }
    for (int j = 0; j < m; j++) {
        printf("%d ", lps[j]);
    }
    return 0;
}
medium
A. 0 0 1 2 1
B. 0 1 0 1 2
C. 0 1 2 3 4
D. 0 0 1 2 0

Solution

  1. Step 1: Compute lps array step-by-step for "ABABC"

    Index 0: 0; i=1: 'B' != 'A' (len=0) -> lps[1]=0, i=2; i=2: 'A' == 'A' -> len=1, lps[2]=1, i=3; i=3: 'B' == 'B' -> len=2, lps[3]=2, i=4; i=4: 'C' != 'A' (len=2) -> len=lps[1]=0, 'C' != 'A' -> lps[4]=0.
  2. Step 2: Final lps array values

    The lps array is [0, 0, 1, 2, 0]. Output: 0 0 1 2 0
  3. Final Answer:

    0 0 1 2 0 -> Option D
  4. Quick Check:

    lps for "ABABC" = 0 0 1 2 0 [OK]
Hint: Trace lps step-by-step for each pattern char [OK]
Common Mistakes:
  • Miscomputing fallback index in lps
  • Confusing pattern characters during comparison
  • Assuming lps always increases
4. Identify the bug in this KMP prefix array computation snippet and select the fix:
int i = 1, len = 0;
while (i <= m) {
    if (pattern[i] == pattern[len]) {
        len++;
        lps[i] = len;
        i++;
    } else {
        if (len != 0) {
            len = lps[len - 1];
        } else {
            lps[i] = 0;
            i++;
        }
    }
}
medium
A. Remove i++ inside else block
B. Initialize len to 1 instead of 0
C. Change loop condition to i < m
D. Use pattern[len+1] instead of pattern[len]

Solution

  1. Step 1: Analyze loop boundary

    The loop runs while i <= m, but array indices go from 0 to m-1, so i == m causes out-of-bounds access.
  2. Step 2: Correct loop condition

    Changing condition to i < m prevents accessing beyond array size.
  3. Final Answer:

    Change loop condition to i < m -> Option C
  4. Quick Check:

    Loop index must be less than array size [OK]
Hint: Loop till less than array size, not equal [OK]
Common Mistakes:
  • Using <= instead of < causing overflow
  • Incorrect initialization of len
  • Misplacing increment statements
5. Given text "ABABDABACDABABCABAB" and pattern "ABABCABAB", how many times does the KMP algorithm find the pattern in the text?
hard
A. 1
B. 2
C. 3
D. 0

Solution

  1. Step 1: Understand pattern occurrences

    Check the text for exact matches of pattern "ABABCABAB" (length 9).
  2. Step 2: Locate matches in text

    Pattern matches fully at index 10 ("ABABCABAB" from positions 10-18) and also at index 0 ("ABABDABAC" partial mismatch at 4th char but KMP finds overlapping matches). Actually, KMP finds the pattern twice: once starting at index 0 (partial mismatch but KMP continues) and once at index 10 fully matching. The correct count is 2.
  3. Final Answer:

    2 -> Option B
  4. Quick Check:

    Pattern found twice in text [OK]
Hint: Count full pattern matches in text using KMP [OK]
Common Mistakes:
  • Counting partial matches as full
  • Misidentifying additional matches (e.g., at index 14)
  • Overlooking text length boundaries
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard