using System; using System.Collections.Generic; class Program { static List<int> NaiveSearch(string text, string pattern) { List<int> positions = new List<int>(); int n = text.Length, m = pattern.Length; for (int i = 0; i <= n - m; i++) { int j; for (j = 0; j < m; j++) { if (text[i + j] != pattern[j]) break; } if (j == m) positions.Add(i); } return positions; } static void Main() { string text = "abracadabra"; string pattern = "abra"; var result = NaiveSearch(text, pattern); Console.WriteLine(string.Join(",", result)); } }
The pattern "abra" appears twice in the text: starting at index 0 and again at index 7. The naive search checks every position and adds the index when a full match is found.
using System; class Program { static int[] ComputeLPS(string pattern) { int m = pattern.Length; int[] lps = new int[m]; int len = 0; int i = 1; 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++; } } } return lps; } static void Main() { string pattern = "ababc"; var lps = ComputeLPS(pattern); Console.WriteLine(string.Join(",", lps)); } }
The lps array for "ababc" is [0,0,1,2,0]. This means at index 2, the longest prefix-suffix length is 1 ("a"), at index 3 it is 2 ("ab"), and so on.
using System; class Program { static int ComputeHash(string s, int prime, int mod) { int hash = 0; for (int i = 0; i < s.Length; i++) { hash = (hash * prime + s[i]) % mod; } return hash; } static void Main() { string text = "hello"; string pattern = "ell"; int prime = 101; int mod = 1000; int patternHash = ComputeHash(pattern, prime, mod); int textHash = ComputeHash(text.Substring(0, pattern.Length), prime, mod); Console.WriteLine($"Pattern hash: {patternHash}, Text hash: {textHash}"); } }
The code computes the initial hash correctly but does not update the hash efficiently for the next substrings. Rabin-Karp requires a rolling hash update to slide over the text.
using System; using System.Collections.Generic; class Program { static Dictionary<char, int> BuildBadCharTable(string pattern) { var table = new Dictionary<char, int>(); int length = pattern.Length; for (int i = 0; i < length - 1; i++) { table[pattern[i]] = length - 1 - i; } return table; } static void Main() { string pattern = "example"; var table = BuildBadCharTable(pattern); foreach (var kvp in table) { Console.WriteLine($"{kvp.Key}:{kvp.Value}"); } } }
The bad character table for "example" assigns distances from the right end for each character except the last 'e'. For example, 'x' is at index 1, so distance is 6 - 1 = 5.
The naive algorithm checks every position and can take O(n*m). KMP preprocesses the pattern and runs in O(n). Boyer-Moore is efficient on average O(n) but can degrade to O(n*m) in worst cases.
