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 →