What a string is
RACECAR the same forwards and backwards? — on every keystroke. So how you reach into a word decides whether the game feels instant or laggy."RACECAR"[0] is 'R', "RACECAR"[6] is 'R', and .length is 7 — exactly like an array.Quick check
The substring "ell" inside "hello" is…
Answer it in the interactive lesson to keep your progress.
The core operations
- read
s[i](ors.charAt(i)) — the character at indexi. - length
s.length— how many characters; the last index islength - 1. - scan — loop
for (const ch of s)to visit each character. - "edit" — you can't do
s[1] = 'a'(it silently does nothing). Instead build a new string, ors.split('')into an array, change it, and.join('')back. - transform —
s.toUpperCase(),s.slice(1, 4), etc. all return a new string; the original is untouched.
const s = "hello";
console.log(s[0]); // "h" (character at index 0)
console.log(s.length); // 5 (how many characters)
// Strings are immutable: s[1] = "a" can't change s — it does nothing.
console.log(s); // still "hello"
const up = s.toUpperCase();
console.log(up, s); // "HELLO" "hello" — the original is unchangedQuick check
Predict: after `let s = "cat"; s[0] = "b";`, what is `s`?
Answer it in the interactive lesson to keep your progress.
Your first string problem: is it a palindrome?
RACECAR. The obvious move — build a reversed copy and compare — works, but it wastes memory building a whole second string. There's a no-copy way: check the two ends against each other and walk inward.The steps
- Put one marker
lon the first character and anotherron the last. - If the characters at
landrdiffer, it's not a palindrome — stop. - Otherwise step inward:
l = l + 1,r = r - 1. - When the markers meet (or cross), every pair matched — it is a palindrome.
Trace it on RACECAR (l=0, r=6):
RvsR— match. Step in:l=1,r=5.AvsA— match.l=2,r=4.CvsC— match.l=3,r=3— markers met.
O(1) extra space (from the Complexity lesson: constant — no second string is built), in at most half a pass, O(n) time. On HELLO the first compare (H vs O) fails and we stop early. In JavaScript, one way to write those steps:l starts at the left end and r at the right. Each step compares the two highlighted characters, and only on a match do both pointers slide one position inward. Before each step, predict which two characters will be compared next — when the pointers meet in the middle, you have your answer.This section has a step-by-step animation in the interactive lesson.
function isPalindrome(s) {
let l = 0, r = s.length - 1;
while (l < r) {
if (s[l] !== s[r]) return false; // mismatch — stop early
l++; // move inward from the left
r--; // move inward from the right
}
return true; // every pair matched
}
console.log(isPalindrome("racecar")); // true
console.log(isPalindrome("hello")); // falseQuick check
Why can two pointers check a palindrome in O(1) extra space?
Answer it in the interactive lesson to keep your progress.
Where it breaks (and how not to get burned)
- Concatenation in a loop. Because strings are immutable,
result += chrebuilds the whole string each time —nof those is a hiddenO(n²). Push characters into an array and.join('')once at the end. - Case and whitespace.
"Madam"isn't a palindrome by raw character compare (Mvsm). Normalize with.toLowerCase()first if it should ignore case. - Assuming one char per code unit. Emoji and accented letters can span two units;
.lengthcounts units, not glyphs.
Quick check
In JavaScript, s[1] = "a" on a string…
Answer it in the interactive lesson to keep your progress.
Take it further — valid anagram
The steps
- If the two words differ in length, they can't be anagrams — stop.
- Count each character of the first word into a map.
- For each character of the second word, subtract one from its count; if a count is missing or already
0, they don't match. - If every character was spent exactly, they're anagrams.
listen / silent:function isAnagram(a, b) {
if (a.length !== b.length) return false;
const count = {};
for (const ch of a) count[ch] = (count[ch] || 0) + 1; // tally a's letters
for (const ch of b) {
if (!count[ch]) return false; // b needs a letter a doesn't have
count[ch]--;
}
return true;
}
console.log(isAnagram('listen', 'silent')); // true
console.log(isAnagram('cat', 'dog')); // falseQuick check
Tallying "listen", you now spend the letters of "silent". Predict: when does the check fail?
Answer it in the interactive lesson to keep your progress.
How fast is it? (complexity)
- read
s[i]/s.length→O(1), constant - scan the whole string (palindrome, counting) →
O(n), linear - build a new string with
+=in a loop →O(n²)trap (a copy per step) — use an array +join
O(n) time, O(1) extra space.- A string is an indexable, immutable row of characters.
- Reading by index is
O(1); changing means building a new string. - Reach for one of three tools: two pointers (compare ends), a frequency map (order doesn't matter), or a sliding window (best contiguous run).
This section has a step-by-step animation in the interactive lesson.