String Manipulation
Master fundamental string operations and character manipulation techniques
Level 1: Foundation - String Manipulation
Basic String Operations
String manipulation involves working with sequences of characters. Understanding basic operations like concatenation, substring extraction, and character access is fundamental to solving string-based problems.
📝 Real-Life Analogy:
Think of strings like sentences in a book. You can read individual letters (characters), combine sentences (concatenation), extract phrases (substrings), or count specific words (character frequency).
TypeScript
// Basic String Operations
// 1. String concatenation
function concatenateStrings(str1: string, str2: string): string {
return str1 + str2;
}
// 2. Substring extraction
function getSubstring(str: string, start: number, end: number): string {
return str.substring(start, end);
}
// 3. Character access
function getCharAt(str: string, index: number): string {
return str[index] || str.charAt(index);
}
// 4. String length
function getStringLength(str: string): number {
return str.length;
}
// 5. String comparison
function compareStrings(str1: string, str2: string): boolean {
return str1 === str2;
}
// 6. Case conversion
function toUpperCase(str: string): string {
return str.toUpperCase();
}
function toLowerCase(str: string): string {
return str.toLowerCase();
}
// 7. Manual string operations (without built-in methods)
function manualConcatenation(str1: string, str2: string): string {
let result = '';
for (let i = 0; i < str1.length; i++) {
result += str1[i];
}
for (let i = 0; i < str2.length; i++) {
result += str2[i];
}
return result;
}
// Examples
console.log(concatenateStrings("Hello", " World")); // "Hello World"
console.log(getSubstring("Programming", 0, 7)); // "Program"
console.log(getCharAt("Hello", 1)); // "e"
console.log(getStringLength("JavaScript")); // 10
Python
# Basic String Operations
# 1. String concatenation
def concatenate_strings(str1: str, str2: str) -> str:
return str1 + str2
# 2. Substring extraction
def get_substring(s: str, start: int, end: int) -> str:
return s[start:end]
# 3. Character access
def get_char_at(s: str, index: int) -> str | None:
return s[index] if 0 <= index < len(s) else None
# 4. String length
def get_string_length(s: str) -> int:
return len(s)
# 5. String comparison
def compare_strings(str1: str, str2: str) -> bool:
return str1 == str2
# 6. Case conversion
def to_upper_case(s: str) -> str:
return s.upper()
def to_lower_case(s: str) -> str:
return s.lower()
# 7. Manual string operations (without built-in methods)
def manual_concatenation(str1: str, str2: str) -> str:
result = ''
for char in str1:
result += char
for char in str2:
result += char
return result
def manual_substring(s: str, start: int, end: int) -> str:
result = ''
for i in range(start, min(end, len(s))):
result += s[i]
return result
# Examples
print(concatenate_strings("Hello", " World")) # "Hello World"
print(get_substring("Programming", 0, 7)) # "Program"
print(get_char_at("Hello", 1)) # "e"
print(get_string_length("Python")) # 6
OCaml
(* Basic String Operations *)
(* 1. String concatenation *)
let concatenate_strings str1 str2 = str1 ^ str2
(* 2. Substring extraction *)
let get_substring s start len = String.sub s start len
(* 3. Character access *)
let get_char_at s index =
if index >= 0 && index < String.length s then Some s.[index]
else None
(* 4. String length *)
let get_string_length s = String.length s
(* 5. String comparison *)
let compare_strings str1 str2 = String.equal str1 str2
(* 6. Case conversion *)
let to_upper_case s = String.uppercase_ascii s
let to_lower_case s = String.lowercase_ascii s
(* 7. Manual string operations *)
let manual_concatenation str1 str2 =
let len1 = String.length str1 in
let len2 = String.length str2 in
let result = Bytes.create (len1 + len2) in
String.blit str1 0 result 0 len1;
String.blit str2 0 result len1 len2;
Bytes.to_string result
let manual_substring s start len =
let s_len = String.length s in
let actual_len = min len (s_len - start) in
if start >= 0 && start < s_len && actual_len > 0 then
let result = Bytes.create actual_len in
String.blit s start result 0 actual_len;
Bytes.to_string result
else ""
(* Examples *)
let example1 = concatenate_strings "Hello" " World";; (* "Hello World" *)
let example2 = get_substring "Programming" 0 7;; (* "Program" *)
let example3 = get_char_at "Hello" 1;; (* Some 'e' *)
let example4 = get_string_length "OCaml";; (* 5 *)
Key String Operations:
- Concatenation: Joining two or more strings together
- Substring: Extracting a portion of a string
- Character Access: Getting individual characters by index
- Length: Determining the number of characters in a string
- Comparison: Checking if two strings are equal
String Traversal and Character Manipulation
String traversal involves iterating through each character in a string to perform operations like counting, searching, or transforming characters.
🚶 Real-Life Analogy:
Think of reading a book page by page, or examining each bead on a necklace one by one. String traversal is like going through each character in sequence to analyze or modify it.
TypeScript
// String Traversal and Character Manipulation
// 1. Character frequency counting
function countCharacterFrequency(str: string): { [key: string]: number } {
const frequency: { [key: string]: number } = {};
for (let i = 0; i < str.length; i++) {
const char = str[i];
frequency[char] = (frequency[char] || 0) + 1;
}
return frequency;
}
// 2. Find first non-repeating character
function findFirstNonRepeating(str: string): string | null {
const frequency = countCharacterFrequency(str);
for (let i = 0; i < str.length; i++) {
if (frequency[str[i]] === 1) {
return str[i];
}
}
return null;
}
// 3. Remove specific characters
function removeCharacter(str: string, charToRemove: string): string {
let result = '';
for (let i = 0; i < str.length; i++) {
if (str[i] !== charToRemove) {
result += str[i];
}
}
return result;
}
// 4. Count vowels and consonants
function countVowelsAndConsonants(str: string): { vowels: number; consonants: number } {
const vowels = 'aeiouAEIOU';
let vowelCount = 0;
let consonantCount = 0;
for (let i = 0; i < str.length; i++) {
const char = str[i];
if (char.match(/[a-zA-Z]/)) {
if (vowels.includes(char)) {
vowelCount++;
} else {
consonantCount++;
}
}
}
return { vowels: vowelCount, consonants: consonantCount };
}
// 5. Replace characters
function replaceCharacter(str: string, oldChar: string, newChar: string): string {
let result = '';
for (let i = 0; i < str.length; i++) {
if (str[i] === oldChar) {
result += newChar;
} else {
result += str[i];
}
}
return result;
}
// Examples
console.log(countCharacterFrequency("hello")); // {h: 1, e: 1, l: 2, o: 1}
console.log(findFirstNonRepeating("abccba")); // null
console.log(findFirstNonRepeating("abcdef")); // "a"
console.log(removeCharacter("hello world", "l")); // "heo word"
console.log(countVowelsAndConsonants("Hello World")); // {vowels: 3, consonants: 7}
Python
# String Traversal and Character Manipulation
# 1. Character frequency counting
def count_character_frequency(s: str) -> dict[str, int]:
frequency = {}
for char in s:
frequency[char] = frequency.get(char, 0) + 1
return frequency
# 2. Find first non-repeating character
def find_first_non_repeating(s: str) -> str | None:
frequency = count_character_frequency(s)
for char in s:
if frequency[char] == 1:
return char
return None
# 3. Remove specific characters
def remove_character(s: str, char_to_remove: str) -> str:
result = ''
for char in s:
if char != char_to_remove:
result += char
return result
# 4. Count vowels and consonants
def count_vowels_and_consonants(s: str) -> dict[str, int]:
vowels = 'aeiouAEIOU'
vowel_count = 0
consonant_count = 0
for char in s:
if char.isalpha():
if char in vowels:
vowel_count += 1
else:
consonant_count += 1
return {'vowels': vowel_count, 'consonants': consonant_count}
# 5. Replace characters
def replace_character(s: str, old_char: str, new_char: str) -> str:
result = ''
for char in s:
if char == old_char:
result += new_char
else:
result += char
return result
# 6. Check if string contains only digits
def is_all_digits(s: str) -> bool:
for char in s:
if not char.isdigit():
return False
return True
# Examples
print(count_character_frequency("hello")) # {'h': 1, 'e': 1, 'l': 2, 'o': 1}
print(find_first_non_repeating("abccba")) # None
print(find_first_non_repeating("abcdef")) # "a"
print(remove_character("hello world", "l")) # "heo word"
print(count_vowels_and_consonants("Hello World")) # {'vowels': 3, 'consonants': 7}
OCaml
(* String Traversal and Character Manipulation *)
(* 1. Character frequency counting *)
let count_character_frequency s =
let freq = Hashtbl.create 16 in
String.iter (fun char ->
let count = try Hashtbl.find freq char with Not_found -> 0 in
Hashtbl.replace freq char (count + 1)
) s;
freq
(* 2. Find first non-repeating character *)
let find_first_non_repeating s =
let freq = count_character_frequency s in
let rec find_first i =
if i >= String.length s then None
else if Hashtbl.find freq s.[i] = 1 then Some s.[i]
else find_first (i + 1)
in
find_first 0
(* 3. Remove specific characters *)
let remove_character s char_to_remove =
let buffer = Buffer.create (String.length s) in
String.iter (fun char ->
if char <> char_to_remove then Buffer.add_char buffer char
) s;
Buffer.contents buffer
(* 4. Count vowels and consonants *)
let count_vowels_and_consonants s =
let vowels = "aeiouAEIOU" in
let is_vowel c = String.contains vowels c in
let is_alpha c = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') in
let vowel_count = ref 0 in
let consonant_count = ref 0 in
String.iter (fun char ->
if is_alpha char then
if is_vowel char then incr vowel_count
else incr consonant_count
) s;
(!vowel_count, !consonant_count)
(* 5. Replace characters *)
let replace_character s old_char new_char =
let buffer = Buffer.create (String.length s) in
String.iter (fun char ->
if char = old_char then Buffer.add_char buffer new_char
else Buffer.add_char buffer char
) s;
Buffer.contents buffer
(* 6. Check if string contains only digits *)
let is_all_digits s =
let rec check i =
if i >= String.length s then true
else if s.[i] >= '0' && s.[i] <= '9' then check (i + 1)
else false
in
check 0
(* Examples *)
let freq_example = count_character_frequency "hello";;
let first_non_rep = find_first_non_repeating "abcdef";; (* Some 'a' *)
let removed = remove_character "hello world" 'l';; (* "heo word" *)
let (vowels, consonants) = count_vowels_and_consonants "Hello World";; (* (3, 7) *)
String Traversal Techniques:
- Linear Traversal: Process each character sequentially
- Frequency Counting: Track occurrences of each character
- Filtering: Remove or replace specific characters
- Classification: Categorize characters (vowels, digits, etc.)
- Pattern Detection: Find specific character patterns
Common String Problems
These are fundamental string manipulation problems that appear frequently in programming interviews and real-world applications.
🧩 Real-Life Analogy:
Think of these problems like word puzzles or games. Reversing a string is like reading a word backwards, checking for palindromes is like finding words that read the same forwards and backwards (like "racecar").
TypeScript
// Common String Problems
// 1. Reverse a string (without built-in methods)
function reverseString(str: string): string {
let result = '';
for (let i = str.length - 1; i >= 0; i--) {
result += str[i];
}
return result;
}
// 2. Check if string is palindrome
function isPalindrome(str: string): boolean {
const cleaned = str.toLowerCase().replace(/[^a-z0-9]/g, '');
let left = 0;
let right = cleaned.length - 1;
while (left < right) {
if (cleaned[left] !== cleaned[right]) {
return false;
}
left++;
right--;
}
return true;
}
// 3. Check if two strings are anagrams
function areAnagrams(str1: string, str2: string): boolean {
if (str1.length !== str2.length) return false;
const freq1 = countCharacterFrequency(str1.toLowerCase());
const freq2 = countCharacterFrequency(str2.toLowerCase());
for (const char in freq1) {
if (freq1[char] !== freq2[char]) {
return false;
}
}
return true;
}
// 4. Find longest common prefix
function longestCommonPrefix(strings: string[]): string {
if (strings.length === 0) return '';
let prefix = '';
const firstString = strings[0];
for (let i = 0; i < firstString.length; i++) {
const char = firstString[i];
for (let j = 1; j < strings.length; j++) {
if (i >= strings[j].length || strings[j][i] !== char) {
return prefix;
}
}
prefix += char;
}
return prefix;
}
// 5. Remove duplicates from string
function removeDuplicates(str: string): string {
const seen = new Set();
let result = '';
for (let i = 0; i < str.length; i++) {
const char = str[i];
if (!seen.has(char)) {
seen.add(char);
result += char;
}
}
return result;
}
// 6. Check if string is a rotation of another
function isRotation(str1: string, str2: string): boolean {
if (str1.length !== str2.length) return false;
const concatenated = str1 + str1;
return concatenated.includes(str2);
}
// Helper function from previous section
function countCharacterFrequency(str: string): { [key: string]: number } {
const frequency: { [key: string]: number } = {};
for (let i = 0; i < str.length; i++) {
const char = str[i];
frequency[char] = (frequency[char] || 0) + 1;
}
return frequency;
}
// Examples
console.log(reverseString("hello")); // "olleh"
console.log(isPalindrome("A man a plan a canal Panama")); // true
console.log(areAnagrams("listen", "silent")); // true
console.log(longestCommonPrefix(["flower", "flow", "flight"])); // "fl"
console.log(removeDuplicates("programming")); // "progamin"
console.log(isRotation("waterbottle", "erbottlewat")); // true
Python
# Common String Problems
# 1. Reverse a string (without built-in methods)
def reverse_string(s: str) -> str:
result = ''
for i in range(len(s) - 1, -1, -1):
result += s[i]
return result
# 2. Check if string is palindrome
def is_palindrome(s):
# Clean the string: remove non-alphanumeric and convert to lowercase
cleaned = ''.join(char.lower() for char in s if char.isalnum())
left, right = 0, len(cleaned) - 1
while left < right:
if cleaned[left] != cleaned[right]:
return False
left += 1
right -= 1
return True
# 3. Check if two strings are anagrams
def are_anagrams(str1, str2):
if len(str1) != len(str2):
return False
freq1 = count_character_frequency(str1.lower())
freq2 = count_character_frequency(str2.lower())
return freq1 == freq2
# 4. Find longest common prefix
def longest_common_prefix(strings):
if not strings:
return ''
prefix = ''
first_string = strings[0]
for i in range(len(first_string)):
char = first_string[i]
for j in range(1, len(strings)):
if i >= len(strings[j]) or strings[j][i] != char:
return prefix
prefix += char
return prefix
# 5. Remove duplicates from string
def remove_duplicates(s):
seen = set()
result = ''
for char in s:
if char not in seen:
seen.add(char)
result += char
return result
# 6. Check if string is a rotation of another
def is_rotation(str1, str2):
if len(str1) != len(str2):
return False
concatenated = str1 + str1
return str2 in concatenated
# 7. Count words in a string
def count_words(s):
words = s.split()
return len(words)
# 8. Capitalize first letter of each word
def capitalize_words(s):
result = ''
capitalize_next = True
for char in s:
if char.isalpha():
if capitalize_next:
result += char.upper()
capitalize_next = False
else:
result += char.lower()
else:
result += char
capitalize_next = True
return result
# Helper function from previous section
def count_character_frequency(s):
frequency = {}
for char in s:
frequency[char] = frequency.get(char, 0) + 1
return frequency
# Examples
print(reverse_string("hello")) # "olleh"
print(is_palindrome("A man a plan a canal Panama")) # True
print(are_anagrams("listen", "silent")) # True
print(longest_common_prefix(["flower", "flow", "flight"])) # "fl"
print(remove_duplicates("programming")) # "progamin"
print(is_rotation("waterbottle", "erbottlewat")) # True
print(capitalize_words("hello world")) # "Hello World"
OCaml
(* Common String Problems *)
(* 1. Reverse a string (without built-in methods) *)
let reverse_string s =
let len = String.length s in
let result = Bytes.create len in
for i = 0 to len - 1 do
Bytes.set result i s.[len - 1 - i]
done;
Bytes.to_string result
(* 2. Check if string is palindrome *)
let is_palindrome s =
let is_alnum c = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') in
let to_lower c = if c >= 'A' && c <= 'Z' then char_of_int (int_of_char c + 32) else c in
(* Clean the string *)
let cleaned = Buffer.create (String.length s) in
String.iter (fun c ->
if is_alnum c then Buffer.add_char cleaned (to_lower c)
) s;
let clean_str = Buffer.contents cleaned in
let len = String.length clean_str in
let rec check left right =
if left >= right then true
else if clean_str.[left] <> clean_str.[right] then false
else check (left + 1) (right - 1)
in
check 0 (len - 1)
(* 3. Check if two strings are anagrams *)
let are_anagrams str1 str2 =
if String.length str1 <> String.length str2 then false
else
let freq1 = count_character_frequency (String.lowercase_ascii str1) in
let freq2 = count_character_frequency (String.lowercase_ascii str2) in
Hashtbl.fold (fun char count acc ->
acc && (try Hashtbl.find freq2 char = count with Not_found -> false)
) freq1 true
(* 4. Find longest common prefix *)
let longest_common_prefix strings =
match strings with
| [] -> ""
| first :: rest ->
let rec find_prefix i =
if i >= String.length first then String.sub first 0 i
else
let char = first.[i] in
let rec check_all = function
| [] -> find_prefix (i + 1)
| s :: ss ->
if i >= String.length s || s.[i] <> char then String.sub first 0 i
else check_all ss
in
check_all rest
in
find_prefix 0
(* 5. Remove duplicates from string *)
let remove_duplicates s =
let seen = Hashtbl.create 16 in
let buffer = Buffer.create (String.length s) in
String.iter (fun char ->
if not (Hashtbl.mem seen char) then (
Hashtbl.add seen char true;
Buffer.add_char buffer char
)
) s;
Buffer.contents buffer
(* 6. Check if string is a rotation of another *)
let is_rotation str1 str2 =
if String.length str1 <> String.length str2 then false
else
let concatenated = str1 ^ str1 in
let rec contains_substring s sub start =
if start + String.length sub > String.length s then false
else if String.sub s start (String.length sub) = sub then true
else contains_substring s sub (start + 1)
in
contains_substring concatenated str2 0
(* Examples *)
let reverse_example = reverse_string "hello";; (* "olleh" *)
let palindrome_example = is_palindrome "A man a plan a canal Panama";; (* true *)
let anagram_example = are_anagrams "listen" "silent";; (* true *)
let prefix_example = longest_common_prefix ["flower"; "flow"; "flight"];; (* "fl" *)
let duplicates_example = remove_duplicates "programming";; (* "progamin" *)
let rotation_example = is_rotation "waterbottle" "erbottlewat";; (* true *)
Common String Problem Patterns:
- Reversal: Process string from end to beginning
- Palindrome: Use two-pointer technique from both ends
- Anagrams: Compare character frequencies
- Prefix/Suffix: Compare characters position by position
- Deduplication: Use hash set to track seen characters
- Rotation: Use string concatenation trick
| Problem | Time Complexity | Space Complexity | Key Technique |
|---|---|---|---|
| Reverse String | O(n) | O(n) | Backward iteration |
| Palindrome Check | O(n) | O(1) | Two pointers |
| Anagram Check | O(n) | O(k) | Frequency counting |
| Common Prefix | O(n×m) | O(1) | Character comparison |
| Remove Duplicates | O(n) | O(k) | Hash set tracking |
Ready to practice?
Now that you understand string manipulation fundamentals, let's apply these concepts!
Continue to Practice Focus →