Check whether a String is Palindrome or notEasy2 approaches
Problem
Return true if the string reads the same forwards and backwards.
Example 1
Input: "level" Output: true
Example 2
Input: "hello" Output: false
1. Two pointers
Time O(n)Space O(1)
Compare characters from both ends moving inward.
function isPalindrome(s) { let l = 0, r = s.length - 1; while (l < r) if (s[l++] !== s[r--]) return false; return true;}2. Reverse and compare
Time O(n)Space O(n)
One-liner; O(n) space for the reversed copy. Fine to mention, not the answer they want.
const isPalindrome = (s) => s === [...s].reverse().join('');Write a program to find the longest Palindrome in a stringMedium2 approaches
Problem
Given a string s, return its longest substring that is a palindrome. If several have the same length, return any one of them (commonly the first).
Example 1
Input: "babad" Output: "bab"
"aba" is also correct.
Example 2
Input: "cbbd" Output: "bb"
Also asked as: longest palindromic substring
1. Expand around center
Time O(n²)Space O(1)
Every palindrome has a center (a char, or a gap between two chars). Expand outward from all 2n−1 centers.
function longestPalindrome(s) { let best = ''; const expand = (l, r) => { while (l >= 0 && r < s.length && s[l] === s[r]) { l--; r++; } return s.slice(l + 1, r); }; for (let i = 0; i < s.length; i++) { for (const p of [expand(i, i), expand(i, i + 1)]) if (p.length > best.length) best = p; } return best;}2. Dynamic programming
Time O(n²)Space O(n²)
dp[i][j] = s[i]===s[j] && dp[i+1][j-1]. Fill by substring length. Same time, O(n²) space, easier to reason about.
function longestPalindrome(s) { const n = s.length; const dp = Array.from({ length: n }, () => Array(n).fill(false)); let start = 0, maxLen = 1; for (let i = 0; i < n; i++) dp[i][i] = true; for (let len = 2; len <= n; len++) { for (let i = 0; i + len - 1 < n; i++) { const j = i + len - 1; if (s[i] === s[j] && (len === 2 || dp[i + 1][j - 1])) { dp[i][j] = true; if (len > maxLen) { start = i; maxLen = len; } } } } return s.slice(start, start + maxLen);}Manacher’s algorithm solves this in O(n) but is rarely expected in interviews — mention it exists.
Longest Common PrefixEasy2 approaches
Problem
Given an array of strings, return the longest string that is a prefix of every one of them, or "" if there is none.
Example 1
Input: ["flower", "flow", "flight"] Output: "fl"
Example 2
Input: ["dog", "racecar", "car"] Output: ""
1. Vertical scan
Time O(N·M) chars totalSpace O(1)
Compare column 0 of every string, then column 1, … Stop at the first mismatch or shortest string end.
function longestCommonPrefix(strs) { if (!strs.length) return ''; for (let i = 0; i < strs[0].length; i++) { const c = strs[0][i]; for (const s of strs) if (i === s.length || s[i] !== c) return strs[0].slice(0, i); } return strs[0];}2. Sort, compare first and last
Time O(N log N · M)Space O(1)
After sorting, only the lexicographically smallest and largest strings matter.
function longestCommonPrefix(strs) { if (!strs.length) return ''; strs.sort(); const a = strs[0], b = strs[strs.length - 1]; let i = 0; while (i < a.length && a[i] === b[i]) i++; return a.slice(0, i);}find the smallest window in a string containing all characters of another stringHard1 approach
Problem
Given strings s and t, return the shortest substring of s that contains every character of t, counting duplicates. Return "" if there is no such window.
Example 1
Input: s = "ADOBECODEBANC", t = "ABC" Output: "BANC"
Example 2
Input: s = "a", t = "aa" Output: ""
t needs two a’s, but s has only one.
Also asked as: minimum window substring · smallest window that contains all characters of string itself
1. Sliding window with need-count
Time O(n)Space O(k)
Expand right until the window covers all needed chars, then contract left while it still does, tracking the smallest.
function minWindow(s, t) { const need = new Map(); for (const c of t) need.set(c, (need.get(c) || 0) + 1); let missing = t.length, start = 0, resStart = 0, resLen = Infinity; for (let end = 0; end < s.length; end++) { const c = s[end]; if (need.get(c) > 0) missing--; need.set(c, (need.get(c) || 0) - 1); while (missing === 0) { if (end - start + 1 < resLen) { resLen = end - start + 1; resStart = start; } const lc = s[start++]; need.set(lc, need.get(lc) + 1); if (need.get(lc) > 0) missing++; } } return resLen === Infinity ? '' : s.slice(resStart, resStart + resLen);}Balanced Parenthesis problemEasy1 approach
Problem
The string contains only the brackets ( ) { } [ ]. Return true if every opening bracket is closed by the same type of bracket, in the correct order.
Example 1
Input: "{[()]}"
Output: trueExample 2
Input: "([)]" Output: false
The ( is closed by ] before its own ).
Also asked as: valid parentheses
1. Stack
Time O(n)Space O(n)
Push openers; on a closer, the stack top must be its matching opener.
function isValid(s) { const pair = { ')': '(', ']': '[', '}': '{' }; const st = []; for (const c of s) { if (c === '(' || c === '[' || c === '{') st.push(c); else if (st.pop() !== pair[c]) return false; } return st.length === 0;}Reverse a StringEasy1 approach
Problem
Reverse a string, or an array of characters in place with O(1) extra space.
Example 1
Input: "hello" Output: "olleh"
1. Two pointers (in place on a char array)
Time O(n)Space O(n) for the array
Swap ends inward. JS strings are immutable, so operate on an array.
function reverseString(s) { const a = [...s]; let l = 0, r = a.length - 1; while (l < r) { [a[l], a[r]] = [a[r], a[l]]; l++; r--; } return a.join('');}Find duplicate characters in a stringEasy1 approach
Problem
Print every character that appears more than once in the string, together with how many times it appears.
Example 1
Input: "programming" Output: r: 2, g: 2, m: 2
Also asked as: Find Duplicate characters in a string
1. Frequency map
Time O(n)Space O(k)
Count each character; report those with count > 1.
function duplicates(s) { const freq = new Map(); for (const c of s) freq.set(c, (freq.get(c) || 0) + 1); return [...freq].filter(([, n]) => n > 1).map(([c, n]) => ({ char: c, count: n }));}Check whether one string is a rotation of anotherEasy1 approach
Problem
Return true if s2 can be obtained by rotating s1, that is, by moving some prefix of s1 to its end.
Example 1
Input: s1 = "ABCD", s2 = "CDAB" Output: true
Example 2
Input: s1 = "ABCD", s2 = "ACBD" Output: false
Also asked as: Write a Code to check whether one string is a rotation of another
1. Double-and-search
Time O(n) with a linear substring searchSpace O(n)
b is a rotation of a iff b is a substring of a + a (and lengths match).
function isRotation(a, b) { return a.length === b.length && (a + a).includes(b);}Check whether a string is a valid shuffle of two stringsMedium1 approach
Problem
Given strings s1, s2 and result, return true if result interleaves s1 and s2: it uses all their characters, and the characters of each string keep their original order.
Example 1
Input: s1 = "XY", s2 = "12", result = "1XY2" Output: true
Example 2
Input: s1 = "XY", s2 = "12", result = "Y1X2" Output: false
Y comes before X, which breaks s1’s order.
Also asked as: Write a Program to check whether a string is a valid shuffle of two strings or not
1. Two-pointer merge check
Time O(n)Space O(1)
Walk the result; each character must match the front of a or b (preserving each source’s order).
function isValidShuffle(a, b, result) { if (a.length + b.length !== result.length) return false; let i = 0, j = 0; for (const c of result) { if (i < a.length && a[i] === c) i++; else if (j < b.length && b[j] === c) j++; else return false; } return i === a.length && j === b.length;}This greedy check can miss cases when a and b share a prefix; a fully correct solution uses interleaving DP: dp[i][j] = whether a[..i] + b[..j] forms result[..i+j].
Count and SayMedium1 approach
Problem
The count-and-say sequence starts with "1". Each next term reads the previous term aloud, group by group: "1" is read as "one 1" → "11", which is read as "two 1s" → "21", and so on. Given n, return the nth term.
Example 1
Input: n = 4 Output: "1211"
1 → 11 → 21 → 1211 ("one 2, one 1").
Also asked as: Count and Say problem
1. Iterative run-length encoding
Time O(n · length)Space O(length)
Start from "1"; each next term describes the previous as "<count><digit>" runs.
function countAndSay(n) { let s = '1'; for (let k = 1; k < n; k++) { let next = '', i = 0; while (i < s.length) { let j = i; while (j < s.length && s[j] === s[i]) j++; next += (j - i) + s[i]; i = j; } s = next; } return s;}Longest Repeating SubsequenceMedium1 approach
Problem
Return the length of the longest subsequence that appears at least twice in the string, where the two occurrences never use the same index at the same position.
Example 1
Input: "axxxy" Output: 2
"xx" can be formed from indices (1,2) and again from (2,3).
Also asked as: Find Longest Recurring Subsequence in String · Longest Repeated Subsequence
1. LCS of the string with itself (excluding equal indices)
Time O(n²)Space O(n²)
Run the LCS DP on (s, s) but only count a match when the two indices differ.
function longestRepeatingSubseq(s) { const n = s.length; const dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(0)); for (let i = 1; i <= n; i++) for (let j = 1; j <= n; j++) dp[i][j] = s[i - 1] === s[j - 1] && i !== j ? dp[i - 1][j - 1] + 1 : Math.max(dp[i - 1][j], dp[i][j - 1]); return dp[n][n];}Split a binary string into two substrings with equal 0s and 1sEasy1 approach
Problem
Split a binary string into the maximum number of consecutive pieces so that every piece has equal numbers of 0s and 1s. Return that count, or −1 if the whole string cannot be split this way.
Example 1
Input: "0100110101" Output: 4
"01" + "0011" + "01" + "01".
Also asked as: Split the Binary string into two substring with equal 0’s and 1’s
1. Running counts
Time O(n)Space O(1)
Scan; every time zeros equals ones so far, you can cut. Count such cut points.
function maxSplits(s) { let zeros = 0, ones = 0, cuts = 0; for (const c of s) { c === '0' ? zeros++ : ones++; if (zeros === ones) cuts++; } return zeros === ones ? cuts : -1; // -1 if the whole string can't be balanced}Word Wrap ProblemHard1 approach
Problem
Given word lengths and a line width k, split the words into lines in their original order. Words on a line are separated by one space, and a line may not exceed k characters. The cost of a line is (unused spaces at its end)², and the last line costs nothing. Return the minimum total cost.
Example 1
Input: lengths = [3, 2, 2, 5], k = 6 Output: 10
Lines: [3] (3 spare → 9), [2, 2] (1 spare → 1), [5] (last line → 0).
Also asked as: Word Wrap Problem · Word Wrap Problem [VERY IMP]
1. DP over line breaks
Time O(n²)Space O(n)
dp[i] = min total cost to arrange words i..n. Try every valid end word for the current line; cost = (trailing spaces)² summed over lines (last line free).
function wordWrap(words, width) { const n = words.length; const dp = Array(n + 1).fill(Infinity); dp[n] = 0; for (let i = n - 1; i >= 0; i--) { let lineLen = -1; for (let j = i; j < n; j++) { lineLen += words[j].length + 1; if (lineLen > width) break; const extra = j === n - 1 ? 0 : (width - lineLen) ** 2; dp[i] = Math.min(dp[i], extra + dp[j + 1]); } } return dp[0];}Edit DistanceMedium1 approach
Problem
Given strings a and b, return the minimum number of single-character operations (insert, delete or replace) needed to turn a into b.
Example 1
Input: a = "horse", b = "ros" Output: 3
Replace h→r, delete r, delete e.
Also asked as: EDIT Distance · Transform One String to Another using Minimum Number of Given Operation
1. 2-D DP (Levenshtein)
Time O(n · m)Space O(n · m)
dp[i][j] = edits to turn a[..i] into b[..j]: 0 if chars match on the diagonal, else 1 + min(insert, delete, replace).
function editDistance(a, b) { const n = a.length, m = b.length; const dp = Array.from({ length: n + 1 }, (_, i) => Array(m + 1).fill(0).map((_, j) => (i === 0 ? j : j === 0 ? i : 0))); for (let i = 1; i <= n; i++) for (let j = 1; j <= m; j++) dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]); return dp[n][m];}Next greater number with the same set of digitsMedium1 approach
Problem
Given a number as a string of digits, return the smallest number greater than it that uses exactly the same digits, or "not possible" if none exists.
Example 1
Input: "218765" Output: "251678"
Example 2
Input: "4321" Output: not possible
Also asked as: Find next greater number with same set of digits
1. Next permutation on the digit array
Time O(d)Space O(d)
Identical to "next permutation": find the rightmost ascending pair, swap with the next-larger digit to its right, reverse the suffix.
function nextGreater(numStr) { const a = [...numStr]; let i = a.length - 2; while (i >= 0 && a[i] >= a[i + 1]) i--; if (i < 0) return 'no greater number'; let j = a.length - 1; while (a[j] <= a[i]) j--; [a[i], a[j]] = [a[j], a[i]]; return a.slice(0, i + 1).join('') + a.slice(i + 1).reverse().join('');}Word BreakMedium1 approach
Problem
Given a string s and a dictionary of words, return true if s can be split into a sequence of one or more dictionary words. Each word can be used any number of times.
Example 1
Input: s = "leetcode", dict = ["leet", "code"] Output: true
Example 2
Input: s = "catsandog", dict = ["cats", "dog", "sand", "and", "cat"] Output: false
Also asked as: Word break Problem · Word Break Problem using Backtracking
1. DP over prefixes
Time O(n² · L)Space O(n)
dp[i] = can s[0..i) be segmented. dp[i] is true if some j<i has dp[j] true and s[j..i) is in the dictionary.
function wordBreak(s, wordDict) { const dict = new Set(wordDict); const dp = Array(s.length + 1).fill(false); dp[0] = true; for (let i = 1; i <= s.length; i++) { for (let j = i - 1; j >= 0; j--) { if (dp[j] && dict.has(s.slice(j, i))) { dp[i] = true; break; } } } return dp[s.length];}Rabin–Karp substring searchMedium1 approach
Problem
Find every index where the pattern occurs in the text, using a rolling hash: compare hashes first, and check characters only when the hashes match.
Example 1
Input: text = "AABAACAADAABAABA", pattern = "AABA" Output: [0, 9, 12]
Also asked as: Rabin Karp Algo
1. Rolling hash
Time O(n + m) average, O(n·m) worstSpace O(1)
Hash the pattern and each length-m window of the text; roll the hash in O(1) per shift. On a hash match, verify char-by-char.
function rabinKarp(text, pat) { const n = text.length, m = pat.length; if (m > n) return []; const B = 256, MOD = 1_000_000_007; let pHash = 0, tHash = 0, pow = 1; for (let i = 0; i < m - 1; i++) pow = (pow * B) % MOD; for (let i = 0; i < m; i++) { pHash = (pHash * B + pat.charCodeAt(i)) % MOD; tHash = (tHash * B + text.charCodeAt(i)) % MOD; } const res = []; for (let i = 0; i + m <= n; i++) { if (pHash === tHash && text.slice(i, i + m) === pat) res.push(i); if (i + m < n) { tHash = ((tHash - text.charCodeAt(i) * pow) % MOD + MOD) % MOD; tHash = (tHash * B + text.charCodeAt(i + m)) % MOD; } } return res;}KMP substring searchMedium1 approach
Problem
Find every index where the pattern occurs in the text in O(n + m) time, using the KMP failure (longest proper prefix that is also a suffix) table.
Example 1
Input: text = "ABABDABACDABABCABAB", pattern = "ABABCABAB" Output: [10]
Also asked as: KMP Algo
1. Prefix-function (failure table)
Time O(n + m)Space O(m)
Precompute, for each pattern prefix, the longest proper prefix that is also a suffix. On a mismatch, jump the pattern pointer back using that table instead of restarting.
function kmp(text, pat) { const m = pat.length; const lps = Array(m).fill(0); for (let i = 1, len = 0; i < m; ) { if (pat[i] === pat[len]) lps[i++] = ++len; else if (len) len = lps[len - 1]; else lps[i++] = 0; } const res = []; for (let i = 0, j = 0; i < text.length; ) { if (text[i] === pat[j]) { i++; j++; if (j === m) { res.push(i - m); j = lps[j - 1]; } } else if (j) j = lps[j - 1]; else i++; } return res;}Convert a sentence into its mobile numeric keypad sequenceEasy1 approach
Problem
On an old phone keypad, a letter is typed by pressing its key repeatedly (a = 2, b = 22, c = 222, …, s = 7777, z = 9999), and a space is 0. Convert an uppercase sentence into its key sequence.
Example 1
Input: "GEEKS" Output: "4333355777"
Also asked as: Convert a Sentence into its equivalent mobile numeric keypad sequence
1. Lookup table
Time O(n)Space O(1)
Map each letter to its key presses (a→2, b→22, …); concatenate.
function keypadSequence(sentence) { const keys = ['', '', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']; const map = {}; for (let d = 2; d <= 9; d++) [...keys[d]].forEach((ch, i) => (map[ch] = String(d).repeat(i + 1))); return [...sentence.toLowerCase()].map((c) => (c === ' ' ? '0' : map[c] || '')).join('');}Minimum bracket reversals to balance an expressionMedium1 approach
Problem
The expression contains only { and }. Reversing a bracket changes { to } or } to {. Return the minimum number of reversals needed to balance it, or −1 if that is impossible (an odd length).
Example 1
Input: "}{{}}{{{"
Output: 3Example 2
Input: "{{{"
Output: -1Also asked as: Minimum number of bracket reversals needed to make an expression balanced
1. Reduce, then count leftover open/close
Time O(n)Space O(1)
Cancel every matched "()". From the leftover "}}}...{{{" with c closers and o openers, the answer is ceil(c/2) + ceil(o/2).
function minReversals(s) { if (s.length % 2) return -1; let open = 0, close = 0; for (const c of s) { if (c === '{') open++; else if (open > 0) open--; // matched a pair else close++; // an unmatched '}' } return Math.ceil(open / 2) + Math.ceil(close / 2);}Minimum swaps for bracket balancingMedium1 approach
Problem
The string has n [ and n ] characters. In one swap you may exchange two adjacent characters. Return the minimum number of swaps needed to balance the string.
Example 1
Input: "[]][][" Output: 2
Example 2
Input: "[[][]]" Output: 0
Also asked as: Minimum number of swaps for bracket balancing
1. Track imbalance; each unmatched close costs its distance
Time O(n)Space O(1)
Scan; keep the running balance. On each unmatched "]", the number of swaps needed equals the count of "[" still waiting minus already-fixed — accumulate `imbalance` and add it when balance goes negative.
function minSwaps(s) { let balance = 0, swaps = 0, imbalance = 0; for (const c of s) { if (c === '[') { balance++; if (imbalance > 0) { swaps += imbalance; imbalance--; } } else { balance--; if (balance < 0) imbalance++; } } return swaps;}Count all palindromic subsequencesHard1 approach
Problem
Return how many subsequences of the string are palindromes. Subsequences taken from different index sets count separately, even if they spell the same thing.
Example 1
Input: "abcd" Output: 4
Example 2
Input: "aab" Output: 4
"a", "a", "b" and "aa".
Also asked as: Count All Palindromic Subsequence in a given String
1. Interval DP
Time O(n²)Space O(n²)
dp[i][j] = count in s[i..j]. dp[i][j] = dp[i+1][j] + dp[i][j-1] − dp[i+1][j-1], and +dp[i+1][j-1]+1 when s[i]===s[j].
function countPalindromicSubseq(s) { const n = s.length; const dp = Array.from({ length: n }, () => Array(n).fill(0)); for (let i = 0; i < n; i++) dp[i][i] = 1; for (let len = 2; len <= n; len++) { for (let i = 0; i + len - 1 < n; i++) { const j = i + len - 1; dp[i][j] = dp[i + 1][j] + dp[i][j - 1] - (i + 1 <= j - 1 ? dp[i + 1][j - 1] : 0); if (s[i] === s[j]) dp[i][j] += 1 + (i + 1 <= j - 1 ? dp[i + 1][j - 1] : 0); } } return dp[0][n - 1];}Search a word in a 2D grid of charactersMedium1 approach
Problem
Given a grid of characters and a word, find every cell from which the word can be read in a straight line in any of the 8 directions (horizontal, vertical or diagonal) without changing direction.
Example 1
Input: grid = ["GEEKSFORGEEKS", "GEEKSQUIZGEEK", "IDEQAPRACTICE"], word = "GEEKS" Output: [(0,0), (0,8), (1,0)]
Also asked as: Search a Word in a 2D Grid of characters · Count of number of given string in 2D character array
1. DFS from every cell in 8 directions
Time O(R·C·8·L)Space O(1)
From each cell that matches word[0], walk in a fixed direction matching subsequent characters.
function findWord(grid, word) { const R = grid.length, C = grid[0].length; const dirs = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]]; const hits = []; const ok = (r, c, dr, dc) => { for (let k = 0; k < word.length; k++) { const nr = r + dr * k, nc = c + dc * k; if (nr < 0 || nc < 0 || nr >= R || nc >= C || grid[nr][nc] !== word[k]) return false; } return true; }; for (let r = 0; r < R; r++) for (let c = 0; c < C; c++) if (grid[r][c] === word[0]) for (const [dr, dc] of dirs) if (ok(r, c, dr, dc)) hits.push([r, c, dr, dc]); return hits;}Boyer–Moore pattern searching (bad-character rule)Medium1 approach
Problem
Find every index where the pattern occurs in the text. Use the bad-character rule: on a mismatch, shift the pattern so that the mismatched text character lines up with its last occurrence in the pattern.
Example 1
Input: text = "ABAAABCD", pattern = "ABC" Output: [4]
Also asked as: Boyer Moore Algorithm for Pattern Searching
1. Bad-character heuristic
Time O(n/m) best, O(n·m) worstSpace O(alphabet)
Align the pattern; compare right-to-left. On a mismatch, shift so the mismatched text char lines up with its last occurrence in the pattern (or past it).
function boyerMoore(text, pat) { const n = text.length, m = pat.length; const last = new Map(); for (let i = 0; i < m; i++) last.set(pat[i], i); const res = []; let s = 0; while (s <= n - m) { let j = m - 1; while (j >= 0 && pat[j] === text[s + j]) j--; if (j < 0) { res.push(s); s += m; } else { const lo = last.has(text[s + j]) ? last.get(text[s + j]) : -1; s += Math.max(1, j - lo); } } return res;}Convert Roman numerals to decimalEasy1 approach
Problem
Convert a valid Roman numeral (I=1, V=5, X=10, L=50, C=100, D=500, M=1000) to an integer. A smaller symbol placed before a larger one is subtracted: IV = 4, CM = 900.
Example 1
Input: "MCMXCIV" Output: 1994
M (1000) + CM (900) + XC (90) + IV (4).
Also asked as: Converting Roman Numerals to Decimal
1. Subtract when a smaller value precedes a larger
Time O(n)Space O(1)
Add each symbol’s value, but if it is smaller than the next symbol, subtract it instead.
function romanToInt(s) { const v = { I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000 }; let total = 0; for (let i = 0; i < s.length; i++) { if (i + 1 < s.length && v[s[i]] < v[s[i + 1]]) total -= v[s[i]]; else total += v[s[i]]; } return total;}Minimum flips to make a binary string alternateEasy1 approach
Problem
Return the minimum number of characters to flip so that no two adjacent characters of the binary string are equal.
Example 1
Input: "0001010111" Output: 2
Flip to "0101010101".
Also asked as: Number of flips to make binary string alternate
1. Compare against both alternating patterns
Time O(n)Space O(1)
Count mismatches versus "0101…"; mismatches versus "1010…" is n minus that. Answer is the smaller.
function minFlips(s) { let diff = 0; for (let i = 0; i < s.length; i++) { const expected = i % 2 === 0 ? '0' : '1'; if (s[i] !== expected) diff++; } return Math.min(diff, s.length - diff);}Find the first repeated word in a stringEasy1 approach
Problem
Given a sentence, return the first word that appears again later in the sentence (the earliest second occurrence), or report that no word repeats.
Example 1
Input: "he had had quite enough of this nonsense" Output: "had"
Also asked as: Find the first repeated word in string
1. Set of seen words
Time O(n)Space O(w)
Split on whitespace; the first word already in the set is the answer.
function firstRepeatedWord(s) { const seen = new Set(); for (const w of s.toLowerCase().split(/\s+/)) { if (seen.has(w)) return w; seen.add(w); } return null;}Smallest window containing all distinct characters of itselfMedium1 approach
Problem
Return the length of the smallest substring that contains every distinct character of the whole string.
Example 1
Input: "aabcbcdbca" Output: 4
"dbca" contains a, b, c and d.
Also asked as: Write a program tofind the smallest window that contains all characters of string itself
1. Sliding window over the distinct-count target
Time O(n)Space O(k)
Target = number of distinct characters in the whole string. Expand right until the window has them all, then contract left.
function smallestDistinctWindow(s) { const target = new Set(s).size; const count = new Map(); let have = 0, start = 0, best = s; for (let end = 0; end < s.length; end++) { const c = s[end]; count.set(c, (count.get(c) || 0) + 1); if (count.get(c) === 1) have++; while (have === target) { if (end - start + 1 < best.length) best = s.slice(start, end + 1); const lc = s[start++]; count.set(lc, count.get(lc) - 1); if (count.get(lc) === 0) have--; } } return best;}Rearrange a string so no two adjacent characters are the sameMedium1 approach
Problem
Rearrange the characters of the string so that no two adjacent characters are equal. Return any valid arrangement, or "" if none exists.
Example 1
Input: "aab" Output: "aba"
Example 2
Input: "aaab" Output: ""
Three a’s cannot be separated by a single b.
Also asked as: Rearrange characters in a string such that no two adjacent are same · Leetcode- reorganize strings · reorganize strings
1. Greedy — always place the most frequent remaining char
Time O(n · k)Space O(k)
Repeatedly append the highest-count character that is not the one just placed. Impossible iff some char’s count exceeds ceil(n/2).
function reorganize(s) { const freq = new Map(); for (const c of s) freq.set(c, (freq.get(c) || 0) + 1); let res = '', prev = ''; for (let i = 0; i < s.length; i++) { let best = ''; for (const [c, n] of freq) if (n > 0 && c !== prev && (best === '' || n > freq.get(best))) best = c; if (best === '') return ''; res += best; freq.set(best, freq.get(best) - 1); prev = best; } return res;}With a real max-heap keyed by frequency this is O(n log k).
Minimum characters to add at front to make a string palindromeMedium1 approach
Problem
Return the minimum number of characters that must be added to the front of the string to make it a palindrome.
Example 1
Input: "AACECAAAA" Output: 2
Add "AA" to get "AAAACECAAAA".
Example 2
Input: "ABC" Output: 2
Add "CB" to get "CBABC".
Also asked as: Minimum characters to be added at front to make string palindrome
1. KMP failure function on s + "#" + reverse(s)
Time O(n)Space O(n)
The longest prefix of s that is also a suffix of reverse(s) is the longest palindromic prefix. Characters to add = n − that length.
function minCharsFront(s) { const combined = s + '#' + [...s].reverse().join(''); const lps = Array(combined.length).fill(0); for (let i = 1, len = 0; i < combined.length; ) { if (combined[i] === combined[len]) lps[i++] = ++len; else if (len) len = lps[len - 1]; else lps[i++] = 0; } return s.length - lps[lps.length - 1];}Group all anagrams togetherMedium1 approach
Problem
Given a list of words, group together the words that are anagrams of each other (same letters, rearranged). Return the groups in any order.
Example 1
Input: ["eat", "tea", "tan", "ate", "nat", "bat"] Output: [["eat","tea","ate"], ["tan","nat"], ["bat"]]
Also asked as: Given a sequence of words, print all anagrams together
1. Bucket by sorted characters
Time O(n · k log k)Space O(n · k)
Two words are anagrams iff their sorted-letter strings match; use that as a map key.
function groupAnagrams(words) { const groups = new Map(); for (const w of words) { const key = [...w].sort().join(''); if (!groups.has(key)) groups.set(key, []); groups.get(key).push(w); } return [...groups.values()];}Use a 26-length count vector as the key to drop the sort → O(n·k).
Generate all valid IP addresses from a stringMedium1 approach
Problem
Given a string of digits, return every valid IPv4 address you can form by inserting three dots. Each of the four parts must be between 0 and 255 and must not have a leading zero (so "0" is allowed but "01" is not).
Example 1
Input: "25525511135" Output: ["255.255.11.135", "255.255.111.35"]
Also asked as: Program to generate all possible valid IP addresses from given string
1. Backtracking with 4 segments
Time O(1) — at most 3⁴ splitsSpace O(1)
Place 3 dots. Each of the 4 parts is 1–3 digits, ≤ 255, and has no leading zero (unless it is "0").
function restoreIps(s) { const res = []; const valid = (seg) => seg.length >= 1 && seg.length <= 3 && (seg === '0' || (seg[0] !== '0' && +seg <= 255)); const bt = (start, parts) => { if (parts.length === 4) { if (start === s.length) res.push(parts.join('.')); return; } for (let len = 1; len <= 3 && start + len <= s.length; len++) { const seg = s.slice(start, start + len); if (valid(seg)) bt(start + len, [...parts, seg]); } }; bt(0, []); return res;}Recursively remove all adjacent duplicatesMedium1 approach
Problem
Remove every run of two or more equal adjacent characters. Repeat on the result until no adjacent duplicates remain, then return what is left.
Example 1
Input: "azxxzy" Output: "ay"
Removing "xx" gives "azzy". Removing "zz" gives "ay".
Also asked as: Recursively remove all adjacent duplicates
1. Stack
Time O(n)Space O(n)
Push chars; if the incoming char equals the stack top, pop the whole run instead of pushing (and skip the rest of that run).
function removeAdjacentDuplicates(s) { const st = []; let i = 0; while (i < s.length) { if (st.length && st[st.length - 1] === s[i]) { const dup = s[i]; while (i < s.length && s[i] === dup) i++; st.pop(); } else { st.push(s[i++]); } } return st.join('');}Wildcard string matching (? and *)Hard1 approach
Problem
Return true if the pattern matches the whole string. In the pattern, "?" matches any single character and "*" matches any sequence of characters, including none.
Example 1
Input: s = "adceb", p = "*a*b" Output: true
Example 2
Input: s = "acdcb", p = "a*c?b" Output: false
Also asked as: String matching where one string contains wildcard characters
1. 2-D DP
Time O(n · m)Space O(n · m)
dp[i][j] = does pattern[..j] match text[..i]. "?" matches any single char; "*" matches empty (dp[i][j-1]) or one-more (dp[i-1][j]).
function isMatch(text, pattern) { const n = text.length, m = pattern.length; const dp = Array.from({ length: n + 1 }, () => Array(m + 1).fill(false)); dp[0][0] = true; for (let j = 1; j <= m; j++) if (pattern[j - 1] === '*') dp[0][j] = dp[0][j - 1]; for (let i = 1; i <= n; i++) for (let j = 1; j <= m; j++) { if (pattern[j - 1] === '*') dp[i][j] = dp[i][j - 1] || dp[i - 1][j]; else if (pattern[j - 1] === '?' || pattern[j - 1] === text[i - 1]) dp[i][j] = dp[i - 1][j - 1]; } return dp[n][m];}Number of customers who could not get a computerMedium1 approach
Problem
A café has n computers. The string lists events: the first time a letter appears, that customer arrives; the second time, they leave. An arriving customer takes a free computer, or leaves without one if all are busy (and their later departure changes nothing). Return how many customers could not get a computer.
Example 1
Input: n = 2, "ABBAJJKZKZ" Output: 0
Example 2
Input: n = 1, "GACCBDDBAGEE" Output: 1
A arrives while G is still using the only computer.
Also asked as: Function to find Number of customers who could not get a computer
1. Simulate seats with a set
Time O(n)Space O(seats)
First time a customer id appears they take a seat (if one is free, else they walk away). Second appearance frees the seat.
function turnedAway(seq, k) { const seated = new Set(); const walkedAway = new Set(); let turned = 0; for (const id of seq) { if (seated.has(id)) seated.delete(id); // leaving else if (walkedAway.has(id)) walkedAway.delete(id); // second visit after being turned away else if (seated.size < k) seated.add(id); // gets a seat else { turned++; walkedAway.add(id); } // no seat } return turned;}Check if two strings are isomorphicEasy1 approach
Problem
Two strings are isomorphic if the characters of s can be replaced to get t, using a consistent one-to-one mapping (no two characters map to the same character). Return true if they are.
Example 1
Input: s = "egg", t = "add" Output: true
Example 2
Input: s = "foo", t = "bar" Output: false
Example 3
Input: s = "badc", t = "baba" Output: false
Also asked as: Check if two given strings are isomorphic to each other
1. Two consistency maps
Time O(n)Space O(1)
Each char of a must map to exactly one char of b and vice-versa.
function isIsomorphic(a, b) { if (a.length !== b.length) return false; const ab = new Map(), ba = new Map(); for (let i = 0; i < a.length; i++) { if (ab.has(a[i]) && ab.get(a[i]) !== b[i]) return false; if (ba.has(b[i]) && ba.get(b[i]) !== a[i]) return false; ab.set(a[i], b[i]); ba.set(b[i], a[i]); } return true;}Print all sentences from a list of word listsMedium1 approach
Problem
Given a list of word lists, print every sentence formed by picking exactly one word from each list, in list order.
Example 1
Input: [["you", "we"], ["have", "are"]] Output: "you have", "you are", "we have", "we are"
Also asked as: Recursively print all sentences that can be formed from list of word lists
1. Backtracking across rows
Time O(product of row sizes)Space O(rows)
Pick one word from row i, recurse to row i+1; a complete sentence is one word from every row.
function allSentences(lists) { const res = []; const bt = (row, acc) => { if (row === lists.length) { res.push(acc.join(' ')); return; } for (const w of lists[row]) bt(row + 1, [...acc, w]); }; bt(0, []); return res;}Valid AnagramEasy2 approaches
Problem
Return true if t is an anagram of s — the same characters with the same counts, possibly in a different order.
Example 1
Input: s = "anagram", t = "nagaram" Output: true
Example 2
Input: s = "rat", t = "car" Output: false
1. Sort both
Time O(n log n)Space O(n)
Anagrams have identical sorted forms.
const isAnagram = (s, t) => s.length === t.length && [...s].sort().join('') === [...t].sort().join('');2. Count array
Time O(n)Space O(1) — 26 letters (use a Map for Unicode)
Increment for s, decrement for t; every count must end at zero.
function isAnagram(s, t) { if (s.length !== t.length) return false; const cnt = new Array(26).fill(0); for (let i = 0; i < s.length; i++) { cnt[s.charCodeAt(i) - 97]++; cnt[t.charCodeAt(i) - 97]--; } return cnt.every((c) => c === 0);}First Unique Character in a StringEasy1 approach
Problem
Return the index of the first character that appears exactly once in the string, or −1 if there is none.
Example 1
Input: "leetcode" Output: 0
Example 2
Input: "loveleetcode" Output: 2
Example 3
Input: "aabb" Output: -1
1. Two passes with a count
Time O(n)Space O(1) — alphabet size
Count every character, then return the first index whose count is 1.
function firstUniqChar(s) { const cnt = new Map(); for (const c of s) cnt.set(c, (cnt.get(c) ?? 0) + 1); for (let i = 0; i < s.length; i++) if (cnt.get(s[i]) === 1) return i; return -1;}Encode and Decode StringsMedium1 approach
Problem
Design encode(list of strings) → one string, and decode(that string) → the original list. The strings may contain any character, including whatever you might choose as a delimiter.
Example 1
Input: ["neet", "co#de", ""] Output: decode(encode(input)) returns ["neet", "co#de", ""]
1. Length prefix
Time O(total length)Space O(total length)
Write each string as "<length>#<string>". The decoder reads digits up to "#", then exactly that many characters — so "#" inside a string is harmless.
const encode = (strs) => strs.map((s) => s.length + '#' + s).join('');
function decode(str) { const res = []; let i = 0; while (i < str.length) { const hash = str.indexOf('#', i); const len = Number(str.slice(i, hash)); res.push(str.slice(hash + 1, hash + 1 + len)); i = hash + 1 + len; } return res;}Joining with a delimiter breaks when a string contains the delimiter — say why you rejected it.
Valid PalindromeEasy1 approach
Problem
Return true if the string reads the same forwards and backwards after lowercasing it and removing every character that is not a letter or digit.
Example 1
Input: "A man, a plan, a canal: Panama" Output: true
Example 2
Input: "race a car" Output: false
1. Two pointers, skip non-alphanumerics
Time O(n)Space O(1)
Walk inward from both ends, skipping anything that is not a letter or digit, comparing case-insensitively.
function isPalindrome(s) { const ok = (c) => /[a-z0-9]/i.test(c); let l = 0, r = s.length - 1; while (l < r) { if (!ok(s[l])) l++; else if (!ok(s[r])) r--; else if (s[l].toLowerCase() !== s[r].toLowerCase()) return false; else { l++; r--; } } return true;}Longest Substring Without Repeating CharactersMedium2 approaches
Problem
Return the length of the longest substring (contiguous) that contains no repeated character.
Example 1
Input: "abcabcbb" Output: 3
"abc".
Example 2
Input: "pwwkew" Output: 3
"wke" — "pwke" is a subsequence, not a substring.
1. Window with a set
Time O(n)Space O(alphabet)
Grow right; while the new char is already in the window, remove from the left.
function lengthOfLongestSubstring(s) { const win = new Set(); let l = 0, best = 0; for (let r = 0; r < s.length; r++) { while (win.has(s[r])) win.delete(s[l++]); win.add(s[r]); best = Math.max(best, r - l + 1); } return best;}2. Jump using last-seen index
Time O(n)Space O(alphabet)
Store each char’s last index; on a repeat inside the window, jump l straight past it.
function lengthOfLongestSubstring(s) { const last = new Map(); let l = 0, best = 0; for (let r = 0; r < s.length; r++) { if (last.has(s[r]) && last.get(s[r]) >= l) l = last.get(s[r]) + 1; last.set(s[r], r); best = Math.max(best, r - l + 1); } return best;}Longest Repeating Character ReplacementMedium1 approach
Problem
The string contains uppercase letters. You may replace at most k characters with any letter. Return the length of the longest substring you can make that consists of a single repeated letter.
Example 1
Input: s = "ABAB", k = 2 Output: 4
Example 2
Input: s = "AABABBA", k = 1 Output: 4
Replace the A at index 3: "AABBBBA" contains "BBBB".
1. Window with max frequency
Time O(n)Space O(26)
A window is valid when length − (count of its most common char) ≤ k. maxFreq never needs to decrease: a smaller one cannot produce a longer answer.
function characterReplacement(s, k) { const cnt = new Array(26).fill(0); let l = 0, maxFreq = 0, best = 0; for (let r = 0; r < s.length; r++) { maxFreq = Math.max(maxFreq, ++cnt[s.charCodeAt(r) - 65]); while (r - l + 1 - maxFreq > k) cnt[s.charCodeAt(l++) - 65]--; best = Math.max(best, r - l + 1); } return best;}Permutation in StringMedium1 approach
Problem
Return true if s2 contains some permutation of s1 as a substring — a window of s2 with exactly the same character counts as s1.
Example 1
Input: s1 = "ab", s2 = "eidbaooo" Output: true
"ba".
Example 2
Input: s1 = "ab", s2 = "eidboaoo" Output: false
1. Fixed window of counts
Time O(|s2|)Space O(26)
Slide a window of length |s1| over s2 and compare the 26 counts. Track how many letters match to make each step O(1).
function checkInclusion(s1, s2) { if (s1.length > s2.length) return false; const need = new Array(26).fill(0), win = new Array(26).fill(0); const idx = (c) => c.charCodeAt(0) - 97; for (let i = 0; i < s1.length; i++) { need[idx(s1[i])]++; win[idx(s2[i])]++; } let matches = 0; for (let i = 0; i < 26; i++) if (need[i] === win[i]) matches++; for (let r = s1.length; r < s2.length; r++) { if (matches === 26) return true; for (const [c, d] of [[idx(s2[r]), 1], [idx(s2[r - s1.length]), -1]]) { if (win[c] === need[c]) matches--; win[c] += d; if (win[c] === need[c]) matches++; } } return matches === 26;}Comparing the two 26-arrays on every step is also O(26·n) and is fine to present first.