Design a Text Editor
HardUpdated: Aug 2, 2025
Practice on:
Problem
Design a text editor with a cursor that can do the following:
- Add text to where the cursor is.
- Delete text from where the cursor is (simulating the backspace key).
- Move the cursor either left or right.
When deleting text, only characters to the left of the cursor will be deleted.
The cursor will also remain within the actual text and cannot be moved beyond it. More formally, we have that 0 <= cursor.position <= currentText.length
always holds.
Implement the TextEditor class:
TextEditor()Initializes the object with empty text.void addText(string text)Appendstextto where the cursor is. The cursor ends to the right oftext.int deleteText(int k)Deleteskcharacters to the left of the cursor. Returns the number of characters actually deleted.string cursorLeft(int k)Moves the cursor to the leftktimes. Returns the lastmin(10, len)characters to the left of the cursor, wherelenis the number of characters to the left of the cursor.string cursorRight(int k)Moves the cursor to the rightktimes. Returns the lastmin(10, len)characters to the left of the cursor, wherelenis the number of characters to the left of the cursor.
Examples
Example 1
**Input**
["TextEditor", "addText", "deleteText", "addText", "cursorRight", "cursorLeft", "deleteText", "cursorLeft", "cursorRight"]
[[], ["leetcode"], [4], ["practice"], [3], [8], [10], [2], [6]]
**Output**
[null, null, 4, null, "etpractice", "leet", 4, "", "practi"]
**Explanation**
TextEditor textEditor = new TextEditor(); // The current text is "|". (The '|' character represents the cursor)
textEditor.addText("leetcode"); // The current text is "leetcode|".
textEditor.deleteText(4); // return 4
// The current text is "leet|".
// 4 characters were deleted.
textEditor.addText("practice"); // The current text is "leetpractice|".
textEditor.cursorRight(3); // return "etpractice"
// The current text is "leetpractice|".
// The cursor cannot be moved beyond the actual text and thus did not move.
// "etpractice" is the last 10 characters to the left of the cursor.
textEditor.cursorLeft(8); // return "leet"
// The current text is "leet|practice".
// "leet" is the last min(10, 4) = 4 characters to the left of the cursor.
textEditor.deleteText(10); // return 4
// The current text is "|practice".
// Only 4 characters were deleted.
textEditor.cursorLeft(2); // return ""
// The current text is "|practice".
// The cursor cannot be moved beyond the actual text and thus did not move.
// "" is the last min(10, 0) = 0 characters to the left of the cursor.
textEditor.cursorRight(6); // return "practi"
// The current text is "practi|ce".
// "practi" is the last min(10, 6) = 6 characters to the left of the cursor.
Constraints
1 <= text.length, k <= 40textconsists of lowercase English letters.- At most
2 * 10^4calls in total will be made toaddText,deleteText,cursorLeftandcursorRight.
Follow-up: Could you find a solution with time complexity of O(k) per
call?
Solution
Method 1 – Two Stacks for Efficient Cursor and Text Operations
Intuition
To efficiently support cursor movement, text addition, and deletion, we can use two stacks: one for the text to the left of the cursor and one for the text to the right. This allows all operations to be performed in O(1) or O(k) time, where k is the number of characters moved or deleted.
Approach
- Use two stacks:
leftfor characters to the left of the cursor, andrightfor characters to the right. addText(text): Push each character oftextonto theleftstack.deleteText(k): Pop up tokcharacters from theleftstack and return the number of characters actually deleted.cursorLeft(k): Move up tokcharacters fromlefttorightstack. Return the last up to 10 characters from theleftstack as a string.cursorRight(k): Move up tokcharacters fromrighttoleftstack. Return the last up to 10 characters from theleftstack as a string.
Code
Python
class TextEditor:
def __init__(self):
self.left = [] # stack for text to the left of cursor
self.right = [] # stack for text to the right of cursor
def addText(self, text: str) -> None:
for c in text:
self.left.append(c)
def deleteText(self, k: int) -> int:
cnt = 0
while self.left and cnt < k:
self.left.pop()
cnt += 1
return cnt
def cursorLeft(self, k: int) -> str:
for _ in range(min(k, len(self.left))):
self.right.append(self.left.pop())
return ''.join(self.left[-10:])
def cursorRight(self, k: int) -> str:
for _ in range(min(k, len(self.right))):
self.left.append(self.right.pop())
return ''.join(self.left[-10:])
C++
#include <stack>
#include <string>
using namespace std;
class TextEditor {
stack<char> left, right;
public:
TextEditor() {}
void addText(string text) {
for (char c : text) left.push(c);
}
int deleteText(int k) {
int cnt = 0;
while (!left.empty() && cnt < k) {
left.pop();
cnt++;
}
return cnt;
}
string cursorLeft(int k) {
while (!left.empty() && k--) {
right.push(left.top());
left.pop();
}
string ans;
stack<char> tmp = left;
while (!tmp.empty() && ans.size() < 10) {
ans = tmp.top() + ans;
tmp.pop();
}
return ans;
}
string cursorRight(int k) {
while (!right.empty() && k--) {
left.push(right.top());
right.pop();
}
string ans;
stack<char> tmp = left;
while (!tmp.empty() && ans.size() < 10) {
ans = tmp.top() + ans;
tmp.pop();
}
return ans;
}
};
Java
import java.util.*;
public class TextEditor {
Deque<Character> left = new ArrayDeque<>();
Deque<Character> right = new ArrayDeque<>();
public TextEditor() {}
public void addText(String text) {
for (char c : text.toCharArray()) left.addLast(c);
}
public int deleteText(int k) {
int cnt = 0;
while (!left.isEmpty() && cnt < k) {
left.removeLast();
cnt++;
}
return cnt;
}
public String cursorLeft(int k) {
while (!left.isEmpty() && k-- > 0) right.addFirst(left.removeLast());
StringBuilder sb = new StringBuilder();
Iterator<Character> it = left.descendingIterator();
int cnt = 0;
while (it.hasNext() && cnt < 10) {
sb.append(it.next());
cnt++;
}
return sb.reverse().toString();
}
public String cursorRight(int k) {
while (!right.isEmpty() && k-- > 0) left.addLast(right.removeFirst());
StringBuilder sb = new StringBuilder();
Iterator<Character> it = left.descendingIterator();
int cnt = 0;
while (it.hasNext() && cnt < 10) {
sb.append(it.next());
cnt++;
}
return sb.reverse().toString();
}
}
Go
type TextEditor struct {
left, right []byte
}
func Constructor() TextEditor {
return TextEditor{[]byte{}, []byte{}}
}
func (te *TextEditor) AddText(text string) {
te.left = append(te.left, text...)
}
func (te *TextEditor) DeleteText(k int) int {
cnt := 0
for len(te.left) > 0 && cnt < k {
te.left = te.left[:len(te.left)-1]
cnt++
}
return cnt
}
func (te *TextEditor) CursorLeft(k int) string {
for i := 0; i < k && len(te.left) > 0; i++ {
te.right = append(te.right, te.left[len(te.left)-1])
te.left = te.left[:len(te.left)-1]
}
l := len(te.left)
if l > 10 {
return string(te.left[l-10:])
}
return string(te.left)
}
func (te *TextEditor) CursorRight(k int) string {
for i := 0; i < k && len(te.right) > 0; i++ {
te.left = append(te.left, te.right[len(te.right)-1])
te.right = te.right[:len(te.right)-1]
}
l := len(te.left)
if l > 10 {
return string(te.left[l-10:])
}
return string(te.left)
}
Complexity
- ⏰ Time complexity:
O(k)per operation, wherekis the number of characters moved or deleted. - 🧺 Space complexity:
O(n), wherenis the total number of characters in the editor.