Leetcode/Guide/Strings

Last edited by dave on 08/11/2025, 16:24:30 UTC

Leetcode / Guide / Strings

Contents

This guide focuses on practical patterns and reusable functions for common string interview problems.
All examples avoid classes, use descriptive variable names, and rely on for/while where helpful.


🧠 Core Facts You’ll Use Constantly

  • Strings are immutable in JS. To “modify,” build a new string (or work with arrays).
  • Indexing: text[i] and text.charCodeAt(i) are O(1).
  • Case handling: normalize early with .toLowerCase() / .toUpperCase().
  • Trim & split: text.trim(), text.split(' ') (be careful with multiple spaces—use regex if needed).
  • Join: array.join('') to rebuild strings efficiently.
  • Two pointers & sliding window work great for substring constraints.

Handy Helpers

Character Frequency Map (ASCII-ish)

function buildFrequencyMapLowercaseLetters(inputText) { const frequencyMap = new Array(26).fill(0); for (let index = 0; index < inputText.length; index++) { const code = inputText.charCodeAt(index) - 97; // 'a' → 97 if (code >= 0 && code < 26) frequencyMap[code]++; } return frequencyMap; }

Generic Frequency (Object)

function buildFrequencyMapGeneric(inputText) { const frequencyMap = Object.create(null); for (let index = 0; index < inputText.length; index++) { const character = inputText[index]; frequencyMap[character] = (frequencyMap[character] || 0) + 1; } return frequencyMap; }

Classic Problems & Patterns

1) Reverse a String (Two Pointers)

function reverseStringCharacters(inputText) { const characters = inputText.split(''); for ( let leftIndex = 0, rightIndex = characters.length - 1; leftIndex < rightIndex; leftIndex++, rightIndex-- ) { const temporaryCharacter = characters[leftIndex]; characters[leftIndex] = characters[rightIndex]; characters[rightIndex] = temporaryCharacter; } return characters.join(''); } // Demo console.log(reverseStringCharacters("hello")); // "olleh"

2) Palindrome Check (Ignore Non-Alphanumerics, Case-Insensitive)

function isCleanPalindrome(inputText) { let leftIndex = 0; let rightIndex = inputText.length - 1; while (leftIndex < rightIndex) { while (leftIndex < rightIndex && !isAlphaNumeric(inputText[leftIndex])) leftIndex++; while (leftIndex < rightIndex && !isAlphaNumeric(inputText[rightIndex])) rightIndex--; if (inputText[leftIndex].toLowerCase() !== inputText[rightIndex].toLowerCase()) { return false; } leftIndex++; rightIndex--; } return true; } function isAlphaNumeric(character) { const code = character.charCodeAt(0); const isDigit = code >= 48 && code <= 57; const isUpper = code >= 65 && code <= 90; const isLower = code >= 97 && code <= 122; return isDigit || isUpper || isLower; } // Demo console.log(isCleanPalindrome("A man, a plan, a canal: Panama")); // true

3) Anagram Check (Two Strings)

function areAnagrams(textA, textB) { if (textA.length !== textB.length) return false; const frequencyMap = Object.create(null); for (let i = 0; i < textA.length; i++) { const charA = textA[i].toLowerCase(); frequencyMap[charA] = (frequencyMap[charA] || 0) + 1; } for (let j = 0; j < textB.length; j++) { const charB = textB[j].toLowerCase(); if (!frequencyMap[charB]) return false; frequencyMap[charB]--; } return true; } // Demo console.log(areAnagrams("Listen", "Silent")); // true

4) Find All Anagram Indices (Sliding Window)

function findAllAnagramStartIndices(sourceText, patternText) { if (patternText.length > sourceText.length) return []; const needed = Object.create(null); for (let i = 0; i < patternText.length; i++) { const c = patternText[i].toLowerCase(); needed[c] = (needed[c] || 0) + 1; } const resultIndices = []; let matchedUniqueCharacters = 0; const totalUniqueNeeded = Object.keys(needed).length; let windowStartIndex = 0; const windowCounts = Object.create(null); for (let windowEndIndex = 0; windowEndIndex < sourceText.length; windowEndIndex++) { const endChar = sourceText[windowEndIndex].toLowerCase(); windowCounts[endChar] = (windowCounts[endChar] || 0) + 1; if (needed[endChar] && windowCounts[endChar] === needed[endChar]) { matchedUniqueCharacters++; } // shrink when window size exceeds pattern length while (windowEndIndex - windowStartIndex + 1 > patternText.length) { const startChar = sourceText[windowStartIndex].toLowerCase(); if (needed[startChar] && windowCounts[startChar] === needed[startChar]) { matchedUniqueCharacters--; } windowCounts[startChar]--; windowStartIndex++; } if (matchedUniqueCharacters === totalUniqueNeeded && (windowEndIndex - windowStartIndex + 1) === patternText.length) { resultIndices.push(windowStartIndex); } } return resultIndices; } // Demo console.log(findAllAnagramStartIndices("cbaebabacd", "abc")); // [0, 6]

5) Longest Substring Without Repeating Characters (Sliding Window)

function findLengthOfLongestSubstringWithoutRepeats(inputText) { let windowStartIndex = 0; let longestLengthFound = 0; const lastSeenIndexOf = Object.create(null); for (let windowEndIndex = 0; windowEndIndex < inputText.length; windowEndIndex++) { const currentCharacter = inputText[windowEndIndex]; if (lastSeenIndexOf[currentCharacter] !== undefined && lastSeenIndexOf[currentCharacter] >= windowStartIndex) { windowStartIndex = lastSeenIndexOf[currentCharacter] + 1; } lastSeenIndexOf[currentCharacter] = windowEndIndex; const currentWindowLength = windowEndIndex - windowStartIndex + 1; if (currentWindowLength > longestLengthFound) { longestLengthFound = currentWindowLength; } } return longestLengthFound; } // Demo console.log(findLengthOfLongestSubstringWithoutRepeats("abcabcbb")); // 3

6) Longest Repeating Character Replacement (At Most k Changes)

function findLongestSubstringAfterKReplacements(inputText, maxReplacements) { let windowStartIndex = 0; let maxSameCharCountInWindow = 0; let longestLengthFound = 0; const frequencyMap = Object.create(null); for (let windowEndIndex = 0; windowEndIndex < inputText.length; windowEndIndex++) { const endChar = inputText[windowEndIndex]; frequencyMap[endChar] = (frequencyMap[endChar] || 0) + 1; if (frequencyMap[endChar] > maxSameCharCountInWindow) { maxSameCharCountInWindow = frequencyMap[endChar]; } while ((windowEndIndex - windowStartIndex + 1) - maxSameCharCountInWindow > maxReplacements) { const startChar = inputText[windowStartIndex]; frequencyMap[startChar]--; windowStartIndex++; } const currentWindowLength = windowEndIndex - windowStartIndex + 1; if (currentWindowLength > longestLengthFound) { longestLengthFound = currentWindowLength; } } return longestLengthFound; } // Demo console.log(findLongestSubstringAfterKReplacements("AABABBA", 1)); // 4

7) String Compression (Run-Length Encoding)

function runLengthEncode(inputText) { if (inputText.length === 0) return ""; let resultBuilder = []; let runCount = 1; for (let index = 1; index <= inputText.length; index++) { if (inputText[index] === inputText[index - 1]) { runCount++; } else { resultBuilder.push(inputText[index - 1] + String(runCount)); runCount = 1; } } return resultBuilder.join(''); } // Demo console.log(runLengthEncode("aaabbccccd")); // "a3b2c4d1"

8) Valid Parentheses (Stack on String)

function isValidParenthesesSequence(inputText) { const stack = []; const matching = { ')': '(', ']': '[', '}': '{' }; const openers = new Set(['(', '[', '{']); for (let index = 0; index < inputText.length; index++) { const ch = inputText[index]; if (openers.has(ch)) { stack.push(ch); } else if (matching[ch]) { if (stack.length === 0 || stack[stack.length - 1] !== matching[ch]) return false; stack.pop(); } } return stack.length === 0; } // Demo console.log(isValidParenthesesSequence("({[]})")); // true

9) Check Isomorphic Strings

function areIsomorphicStrings(textA, textB) { if (textA.length !== textB.length) return false; const mapAtoB = Object.create(null); const mapBtoA = Object.create(null); for (let i = 0; i < textA.length; i++) { const a = textA[i], b = textB[i]; if ((mapAtoB[a] && mapAtoB[a] !== b) || (mapBtoA[b] && mapBtoA[b] !== a)) { return false; } mapAtoB[a] = b; mapBtoA[b] = a; } return true; } // Demo console.log(areIsomorphicStrings("egg", "add")); // true console.log(areIsomorphicStrings("foo", "bar")); // false

10) Longest Palindromic Substring (Expand Around Center)

function findLongestPalindromicSubstring(inputText) { if (inputText.length < 2) return inputText; let bestStartIndex = 0; let bestLength = 1; function expandFromCenter(leftIndex, rightIndex) { while (leftIndex >= 0 && rightIndex < inputText.length && inputText[leftIndex] === inputText[rightIndex]) { leftIndex--; rightIndex++; } // now [leftIndex+1, rightIndex-1] is palindrome const currentStart = leftIndex + 1; const currentLength = rightIndex - leftIndex - 1; if (currentLength > bestLength) { bestLength = currentLength; bestStartIndex = currentStart; } } for (let center = 0; center < inputText.length; center++) { expandFromCenter(center, center); // odd length expandFromCenter(center, center + 1); // even length } return inputText.slice(bestStartIndex, bestStartIndex + bestLength); } // Demo console.log(findLongestPalindromicSubstring("babad")); // "bab" or "aba"

Quick Tactics Checklist

  • Normalize early: lowercase/trim/strip non-alphanumerics if the spec allows.
  • Two pointers: palindrome, reverse, comparing ends.
  • Sliding window: “longest/shortest substring with constraint”.
  • Frequency maps: anagrams, composition checks.
  • Stacks: parentheses/bracket validation, decoding nested patterns.
  • Center expansion: palindromes.
  • Build with arrays: push chars and .join('') (faster than string concatenation in tight loops).

Complexity Cheats

PatternTypical TimeTypical Space
Two PointersO(n)O(1)
Sliding WindowO(n)O(k) (map)
Frequency MapO(n)O(ÎŁ) (alphabet size)
Stack (parentheses)O(n)O(n)
Center Expand (palindrome)O(n²) worstO(1)

“Gotchas” to Remember

  • String immutability → prefer arrays for heavy edits.
  • Unicode edge cases (emoji/surrogates) can break length/indexing; most coding tests ignore this, but note it.
  • Regex splits: text.trim().split(/\s+/) handles multiple spaces.

Mini Template for New Problems

function solveStringProblem(inputText) { // 1) Normalize if allowed // const normalizedText = inputText.toLowerCase().replace(/[^a-z0-9]/g, ''); // 2) Pick a pattern: two pointers / sliding window / stack / frequency map // 3) Write small helpers if needed (e.g., frequency map) // 4) Implement with clear variables and for/while loops // return resultValue; }

Use these snippets as building blocks, adapt variable names to be explicit, and you’ll move faster in string-heavy coding tests. Good luck! 🚀

Backlinks (1)
Categories (0)

    No categories assigned to this page.

Edit Level

> Signed In Users