The problem. Given an array of characters chars, compress it in place: replace every run of the same character with the character followed by the run's length — but a run of one is just the character. Lengths of 10 or more take one cell per digit. Return the new length; only that many cells at the front count.
chars = ["a","a","b","b","c","c","c"] -> 6, chars starts ["a","2","b","2","c","3"]
chars = ["a"] -> 1, ["a"]
chars = ["a","b","b","b","b","b","b","b","b","b","b","b","b"]
-> 4, ["a","b","1","2"] (12 takes two cells)Scan the runs left to right. A read pointer moves over each run to measure it; a write pointer writes the compressed form back at the front of the same array. This is safe because the compressed form of a run is never longer than the run itself — "aa" becomes "a2", and "aaaaaaaaaaaa" (12) becomes "a12" — so write can never overtake read and overwrite characters that haven't been read yet.
function compress(chars) { const parts = []; let i = 0; while (i < chars.length) { let j = i; while (j < chars.length && chars[j] === chars[i]) j++; // chars[i..j-1] is one run parts.push(chars[i]); if (j - i > 1) parts.push(String(j - i)); i = j; } const result = parts.join(""); // O(n) extra memory for (let k = 0; k < result.length; k++) chars[k] = result[k]; // copy back into chars return result.length;}Time O(n), space O(n). Correct and simple, but the problem asks for O(1) extra space, and the builder is as big as the output.
read measures each run; write puts the compressed form at the front. Try a run longer than 9.
function compress(chars) { let write = 0, read = 0; while (read < chars.length) { const ch = chars[read]; let run = 0; while (read < chars.length && chars[read] === ch) { // measure the run of ch read++; run++; } chars[write++] = ch; // write the character once... if (run > 1) { for (const digit of String(run)) chars[write++] = digit; // ...then its count, digit by digit } } return write; // the compressed length}Time O(n), space O(1). read passes each character once and write writes each output cell once. Turning the count into digits costs O(log run) per run, which never exceeds the run's own length.
The read/write pointer pair is one of the most reusable tricks for in-place array and string edits: Remove Duplicates, Move Zeroes and Remove Element all use it.
"12" is '1', '2'.["a","b","c"] stays as it is, length 3."aabaa" is a2 b a2: runs only join neighbours."21" is one 2, one 1 → "1211". The same run scan, repeated.