String algorithms — palindrome, anagram, substring search
Intermediate5 min read·eng-08-006
interview
Concept
String algorithms — problems involving character arrays, substrings, and pattern matching appear frequently in PHP development and interviews.
Palindrome: A string that reads the same forward and backward. Check: two-pointer from both ends. Expand around center for longest palindromic substring.
Anagram: Two strings with the same characters in possibly different order. Check: sort both and compare (O(n log n)), OR count character frequencies and compare (O(n)).
Substring search:
- Naive:
O(n × m)— for each position in the haystack, check if needle matches. strpos()in PHP: Highly optimized C, but worst caseO(n × m).- KMP (Knuth-Morris-Pratt):
O(n + m)— precomputes a failure function to avoid backtracking. str_contains(),str_starts_with(),str_ends_with()(PHP 8.0+): Prefer these for simple checks.
PHP string functions (all important to know):
strlen(): Length in bytes. Usemb_strlen()for multibyte (UTF-8).substr(): Slice. Usemb_substr()for multibyte.str_replace(): Replace all occurrences.preg_match()/preg_replace(): Regex-based.explode()/implode(): Split/join.strtolower()/strtoupper(): Case. Usemb_*variants for UTF-8.trim()/ltrim()/rtrim(): Remove whitespace.str_word_count(): Count words.similar_text()/levenshtein(): String similarity/distance.
String immutability in PHP: PHP strings are immutable in practice (assigning to $str[0] creates a copy). Concatenation in a loop is O(n²) — use arrays + implode() for large string building.
Code Example
php
<?php
// Palindrome check — O(n)
function isPalindrome(string $s): bool
{
$s = strtolower(preg_replace('/[^a-z0-9]/i', '', $s));
return $s === strrev($s);
}
// Anagram check — O(n) using character count
function isAnagram(string $a, string $b): bool
{
if (strlen($a) !== strlen($b)) return false;
$count = array_fill_keys(str_split($a), 0);
foreach (str_split($a) as $c) $count[$c]++;
foreach (str_split($b) as $c) {
if (!isset($count[$c]) || --$count[$c] < 0) return false;
}
return true;
}
echo isAnagram('listen', 'silent'); // true
echo isAnagram('hello', 'world'); // false
// Group anagrams — O(n × k log k) where k = max string length
function groupAnagrams(array $words): array
{
$groups = [];
foreach ($words as $word) {
$key = str_split($word);
sort($key);
$groups[implode('', $key)][] = $word;
}
return array_values($groups);
}
$grouped = groupAnagrams(['eat', 'tea', 'tan', 'ate', 'nat', 'bat']);
// [['eat','tea','ate'], ['tan','nat'], ['bat']]
// Reverse words in a sentence — O(n)
function reverseWords(string $sentence): string
{
return implode(' ', array_reverse(array_filter(explode(' ', $sentence))));
}
echo reverseWords('the sky is blue'); // 'blue is sky the'
// Efficient string building — O(n) using array + implode
function buildLargeString(int $n): string
{
$parts = [];
for ($i = 0; $i < $n; $i++) {
$parts[] = "item{$i}"; // O(1) array append
}
return implode(', ', $parts); // O(n) single pass
// Avoid: $str .= "item{$i}"; — O(n²) total for large n (copies growing string each time)
}
// Levenshtein distance — minimum edits to transform a to b
echo levenshtein('kitten', 'sitting'); // 3
echo similar_text('Hello', 'World'); // returns number of matching chars
// PHP 8+ clean string checks
$url = 'https://example.com/api/users';
echo str_starts_with($url, 'https://'); // true
echo str_ends_with($url, 'users'); // true
echo str_contains($url, '/api/'); // true
// Multibyte safe operations for UTF-8
$emoji = 'Hello 🌍';
echo strlen($emoji); // bytes (wrong for char count with emoji)
echo mb_strlen($emoji); // 8 (correct character count)