Reported September 2026
Replitstack

Compress Editor Actions into Operational Transform Operations

Reported by candidates from Replit's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.

Get StealthCoderRuns invisibly during the live Replit OA. Under 2s to a working solution.
Founder's read

Replit reported this one in September 2026, and the question looks like a text-editor puzzle but it's really a stack problem in disguise. You get a document, a list of cursor actions, and you have to emit compressed INSERT, DELETE and SKIP rows. The catch is that BACKSPACE can cancel an insert or flip an original character to deleted, and adjacent same-type ops have to merge. If you're staring at this invite, read the next part twice. StealthCoder is there as a quiet safety net during the live OA if your mind goes blank on the stack bookkeeping.

The problem

You are given an original text document and a finite sequence of editor actions. A cursor starts immediately before the first character of document. Convert the actions into a compressed sequence of Operational Transform operations against the original document.
Each action is one of the following rows:
["APPEND", ch] inserts the one-character string ch at the cursor and moves the cursor after it.
["RIGHT"] moves the cursor over the next original-document character. If no original character remains to the right, it does nothing.
["BACKSPACE"] removes the character immediately to the left of the cursor. If that character was inserted by an unmatched APPEND, the insertion is canceled. Otherwise, that original-document character becomes deleted. If there is no character to the left, the action does nothing.
Return rows representing the transformation:
["INSERT", text] inserts text.
["DELETE", count] deletes count original characters.
["SKIP", count] keeps count original characters.
The count value is a positive decimal string. Merge every pair of adjacent operations with the same type: concatenate text for INSERT, and add counts for DELETE or SKIP. Omit canceled inserts, zero-count operations, and actions that do nothing. The unvisited suffix of document is unchanged implicitly, so do not append a final SKIP for it.

Function
compressEditorActions(document: String, actions: String[][]) → String[][]

Examples
Example 1
document = "abcd"
actions = [["APPEND","x"],["APPEND","y"],["RIGHT"],["BACKSPACE"],["APPEND","z"],["RIGHT"]]
return = [["INSERT","xy"],["DELETE","1"],["INSERT","z"],["SKIP","1"]]
The two initial appends merge into INSERT xy. Moving right crosses a, and the following backspace deletes that original character, so it becomes DELETE 1. Then z is inserted and b is kept.
Example 2
document = "abc"
actions = [["RIGHT"],["RIGHT"],["BACKSPACE"],["BACKSPACE"],["BACKSPACE"]]
return = [["DELETE","2"]]
The cursor first crosses a and b. Two backspaces delete them in reverse cursor order, and the adjacent deletions merge into DELETE 2. The final backspace has nothing left to remove.
Example 3
document = "ab"
actions = [["RIGHT"],["APPEND","x"],["BACKSPACE"],["RIGHT"],["RIGHT"],["APPEND","y"]]
return = [["SKIP","2"],["INSERT","y"]]
The first RIGHT keeps a. The inserted x is immediately canceled by backspace. The next successful RIGHT keeps b, the extra RIGHT does nothing at the end, and y remains inserted.

Constraints
0 <= document.length <= 100000.
0 <= actions.length <= 100000.
document contains only lowercase English letters.
Every action is exactly ["RIGHT"], ["BACKSPACE"], or ["APPEND", ch], where ch is one lowercase English letter.
The sum of document.length and the number of APPEND actions is at most 200000.

Reported by candidates. Source: FastPrep

Pattern and pitfall

The structure that carries this solution is a stack of operations to the left of the cursor. Each entry is a token: an inserted character, a skipped original character, or a deleted original character. APPEND pushes an insert. RIGHT pushes a skip and advances a pointer into the document, if one remains. BACKSPACE looks at the top. If it's an insert, pop it, which cancels it. If it's a skip, flip it to a delete. If it's a delete or the stack is empty, do nothing, because deleted characters are already behind the cursor. Careful here: after a delete the next backspace must reach further left, so skip over trailing deletes to find the nearest skip or insert. Then run through the stack once and merge adjacent same-type ops. Drop trailing SKIPs per the unchanged-suffix rule. It's linear. The pitfall is merging too early. If you blank on the cancel-versus-delete logic, StealthCoder can cover you during the live OA.

Memorize the pattern. If you can't, run StealthCoder. The proctor sees the IDE. They don't see what's behind it.

If this hits your live OA

You can drill Compress Editor Actions into Operational Transform Operations cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Made by an engineer who treats the OA as theater. If yours is tonight, you don't have time to grind. You have time to hedge.

Get StealthCoder
⏵ The honest play

You've seen the question. Make sure you actually pass Replit's OA.

Replit reuses patterns across OAs. Made by an engineer who treats the OA as theater. If yours is tonight, you don't have time to grind. You have time to hedge. Works on HackerRank, CodeSignal, CoderPad, and Karat.

Compress Editor Actions into Operational Transform Operations FAQ

What's the trick in the Replit compress editor actions problem?+

Model everything left of the cursor as a stack of tokens: insert, skip, or delete. APPEND pushes, RIGHT pushes a skip, BACKSPACE either pops an insert or converts a skip into a delete. Merge adjacent same-type tokens only at the end, in one pass.

How does BACKSPACE behave after a delete?+

Example 2 shows it. After two backspaces delete a and b, the third has nothing to remove. So BACKSPACE must find the nearest token to the left that is still alive, meaning an insert or a skip. Deleted tokens are ignored. Track a count of live tokens or scan past deletes.

Do I add a final SKIP for the leftover document?+

No. The unvisited suffix is unchanged implicitly, so you never emit a trailing SKIP for characters the cursor never crossed. But a SKIP in the middle, followed by other ops, stays. Trailing skips from RIGHT moves, as in Example 3, are kept since they're followed by or are part of visited text.

What's the time complexity I should aim for?+

Linear. Document length plus APPEND count can reach 200000, and actions can reach 100000, so anything quadratic like rescanning left on every backspace risks timing out. Keep a stack with a pointer to the last live entry, and amortized work stays O(n).

How do I prepare for this in 48 hours?+

Hand-trace the three examples until the stack states feel automatic. Then write the code and test edge cases: empty document, backspace at the start, RIGHT at the end, and an insert canceled then re-added. Check that your merge step handles INSERT text concatenation and counts as decimal strings.

Problem reported by candidates from a real Online Assessment. Sourced from a publicly-available candidate-aggregated repository. Not affiliated with Replit.

OA at Replit?
Invisible during screen share
Get it