{ "data": { "question": { "questionId": "2389", "questionFrontendId": "2296", "categoryTitle": "Algorithms", "boundTopicId": 1531422, "title": "Design a Text Editor", "titleSlug": "design-a-text-editor", "content": "
Design a text editor with a cursor that can do the following:
\n\nWhen 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)
Appends text
to where the cursor is. The cursor ends to the right of text
.int deleteText(int k)
Deletes k
characters to the left of the cursor. Returns the number of characters actually deleted.string cursorLeft(int k)
Moves the cursor to the left k
times. Returns the last min(10, len)
characters to the left of the cursor, where len
is the number of characters to the left of the cursor.string cursorRight(int k)
Moves the cursor to the right k
times. Returns the last min(10, len)
characters to the left of the cursor, where len
is the number of characters to the left of the cursor.\n
Example 1:
\n\n\nInput\n["TextEditor", "addText", "deleteText", "addText", "cursorRight", "cursorLeft", "deleteText", "cursorLeft", "cursorRight"]\n[[], ["leetcode"], [4], ["practice"], [3], [8], [10], [2], [6]]\nOutput\n[null, null, 4, null, "etpractice", "leet", 4, "", "practi"]\n\nExplanation\nTextEditor textEditor = new TextEditor(); // The current text is "|". (The '|' character represents the cursor)\ntextEditor.addText("leetcode"); // The current text is "leetcode|".\ntextEditor.deleteText(4); // return 4\n // The current text is "leet|". \n // 4 characters were deleted.\ntextEditor.addText("practice"); // The current text is "leetpractice|". \ntextEditor.cursorRight(3); // return "etpractice"\n // The current text is "leetpractice|". \n // The cursor cannot be moved beyond the actual text and thus did not move.\n // "etpractice" is the last 10 characters to the left of the cursor.\ntextEditor.cursorLeft(8); // return "leet"\n // The current text is "leet|practice".\n // "leet" is the last min(10, 4) = 4 characters to the left of the cursor.\ntextEditor.deleteText(10); // return 4\n // The current text is "|practice".\n // Only 4 characters were deleted.\ntextEditor.cursorLeft(2); // return ""\n // The current text is "|practice".\n // The cursor cannot be moved beyond the actual text and thus did not move. \n // "" is the last min(10, 0) = 0 characters to the left of the cursor.\ntextEditor.cursorRight(6); // return "practi"\n // The current text is "practi|ce".\n // "practi" is the last min(10, 6) = 6 characters to the left of the cursor.\n\n\n
\n
Constraints:
\n\n1 <= text.length, k <= 40
text
consists of lowercase English letters.2 * 104
calls in total will be made to addText
, deleteText
, cursorLeft
and cursorRight
.\n
Follow-up: Could you find a solution with time complexity of O(k)
per call?
请你设计一个带光标的文本编辑器,它可以实现以下功能:
\n\n当删除文本时,只有光标左边的字符会被删除。光标会留在文本内,也就是说任意时候 0 <= cursor.position <= currentText.length
都成立。
请你实现 TextEditor
类:
TextEditor()
用空文本初始化对象。void addText(string text)
将 text
添加到光标所在位置。添加完后光标在 text
的右边。int deleteText(int k)
删除光标左边 k
个字符。返回实际删除的字符数目。string cursorLeft(int k)
将光标向左移动 k
次。返回移动后光标左边 min(10, len)
个字符,其中 len
是光标左边的字符数目。string cursorRight(int k)
将光标向右移动 k
次。返回移动后光标左边 min(10, len)
个字符,其中 len
是光标左边的字符数目。\n\n
示例 1:
\n\n\n输入:\n[\"TextEditor\", \"addText\", \"deleteText\", \"addText\", \"cursorRight\", \"cursorLeft\", \"deleteText\", \"cursorLeft\", \"cursorRight\"]\n[[], [\"leetcode\"], [4], [\"practice\"], [3], [8], [10], [2], [6]]\n输出:\n[null, null, 4, null, \"etpractice\", \"leet\", 4, \"\", \"practi\"]\n\n解释:\nTextEditor textEditor = new TextEditor(); // 当前 text 为 \"|\" 。('|' 字符表示光标)\ntextEditor.addText(\"leetcode\"); // 当前文本为 \"leetcode|\" 。\ntextEditor.deleteText(4); // 返回 4\n // 当前文本为 \"leet|\" 。\n // 删除了 4 个字符。\ntextEditor.addText(\"practice\"); // 当前文本为 \"leetpractice|\" 。\ntextEditor.cursorRight(3); // 返回 \"etpractice\"\n // 当前文本为 \"leetpractice|\". \n // 光标无法移动到文本以外,所以无法移动。\n // \"etpractice\" 是光标左边的 10 个字符。\ntextEditor.cursorLeft(8); // 返回 \"leet\"\n // 当前文本为 \"leet|practice\" 。\n // \"leet\" 是光标左边的 min(10, 4) = 4 个字符。\ntextEditor.deleteText(10); // 返回 4\n // 当前文本为 \"|practice\" 。\n // 只有 4 个字符被删除了。\ntextEditor.cursorLeft(2); // 返回 \"\"\n // 当前文本为 \"|practice\" 。\n // 光标无法移动到文本以外,所以无法移动。\n // \"\" 是光标左边的 min(10, 0) = 0 个字符。\ntextEditor.cursorRight(6); // 返回 \"practi\"\n // 当前文本为 \"practi|ce\" 。\n // \"practi\" 是光标左边的 min(10, 6) = 6 个字符。\n\n\n
\n\n
提示:
\n\n1 <= text.length, k <= 40
text
只含有小写英文字母。addText
,deleteText
,cursorLeft
和 cursorRight
的 总 次数不超过 2 * 104
次。\n\n
进阶:你能设计并实现一个每次调用时间复杂度为 O(k)
的解决方案吗?
\\u7248\\u672c\\uff1a \\u7f16\\u8bd1\\u65f6\\uff0c\\u5c06\\u4f1a\\u91c7\\u7528 \\u4e3a\\u4e86\\u4f7f\\u7528\\u65b9\\u4fbf\\uff0c\\u5927\\u90e8\\u5206\\u6807\\u51c6\\u5e93\\u7684\\u5934\\u6587\\u4ef6\\u5df2\\u7ecf\\u88ab\\u81ea\\u52a8\\u5bfc\\u5165\\u3002<\\/p>\"],\"java\":[\"Java\",\" \\u7248\\u672c\\uff1a \\u4e3a\\u4e86\\u65b9\\u4fbf\\u8d77\\u89c1\\uff0c\\u5927\\u90e8\\u5206\\u6807\\u51c6\\u5e93\\u7684\\u5934\\u6587\\u4ef6\\u5df2\\u88ab\\u5bfc\\u5165\\u3002<\\/p>\\r\\n\\r\\n \\u5305\\u542b Pair \\u7c7b: https:\\/\\/docs.oracle.com\\/javase\\/8\\/javafx\\/api\\/javafx\\/util\\/Pair.html <\\/p>\"],\"python\":[\"Python\",\" \\u7248\\u672c\\uff1a \\u4e3a\\u4e86\\u65b9\\u4fbf\\u8d77\\u89c1\\uff0c\\u5927\\u90e8\\u5206\\u5e38\\u7528\\u5e93\\u5df2\\u7ecf\\u88ab\\u81ea\\u52a8 \\u5bfc\\u5165\\uff0c\\u5982\\uff1aarray<\\/a>, bisect<\\/a>, collections<\\/a>\\u3002\\u5982\\u679c\\u60a8\\u9700\\u8981\\u4f7f\\u7528\\u5176\\u4ed6\\u5e93\\u51fd\\u6570\\uff0c\\u8bf7\\u81ea\\u884c\\u5bfc\\u5165\\u3002<\\/p>\\r\\n\\r\\n \\u6ce8\\u610f Python 2.7 \\u5c06\\u57282020\\u5e74\\u540e\\u4e0d\\u518d\\u7ef4\\u62a4<\\/a>\\u3002 \\u5982\\u60f3\\u4f7f\\u7528\\u6700\\u65b0\\u7248\\u7684Python\\uff0c\\u8bf7\\u9009\\u62e9Python 3\\u3002<\\/p>\"],\"c\":[\"C\",\" \\u7248\\u672c\\uff1a \\u7f16\\u8bd1\\u65f6\\uff0c\\u5c06\\u4f1a\\u91c7\\u7528 \\u4e3a\\u4e86\\u4f7f\\u7528\\u65b9\\u4fbf\\uff0c\\u5927\\u90e8\\u5206\\u6807\\u51c6\\u5e93\\u7684\\u5934\\u6587\\u4ef6\\u5df2\\u7ecf\\u88ab\\u81ea\\u52a8\\u5bfc\\u5165\\u3002<\\/p>\\r\\n\\r\\n \\u5982\\u60f3\\u4f7f\\u7528\\u54c8\\u5e0c\\u8868\\u8fd0\\u7b97, \\u60a8\\u53ef\\u4ee5\\u4f7f\\u7528 uthash<\\/a>\\u3002 \\\"uthash.h\\\"\\u5df2\\u7ecf\\u9ed8\\u8ba4\\u88ab\\u5bfc\\u5165\\u3002\\u8bf7\\u770b\\u5982\\u4e0b\\u793a\\u4f8b:<\\/p>\\r\\n\\r\\n 1. \\u5f80\\u54c8\\u5e0c\\u8868\\u4e2d\\u6dfb\\u52a0\\u4e00\\u4e2a\\u5bf9\\u8c61\\uff1a<\\/b>\\r\\n 2. \\u5728\\u54c8\\u5e0c\\u8868\\u4e2d\\u67e5\\u627e\\u4e00\\u4e2a\\u5bf9\\u8c61\\uff1a<\\/b>\\r\\n 3. \\u4ece\\u54c8\\u5e0c\\u8868\\u4e2d\\u5220\\u9664\\u4e00\\u4e2a\\u5bf9\\u8c61\\uff1a<\\/b>\\r\\n C# 10<\\/a> \\u8fd0\\u884c\\u5728 .NET 6 \\u4e0a<\\/p>\"],\"javascript\":[\"JavaScript\",\" \\u7248\\u672c\\uff1a \\u60a8\\u7684\\u4ee3\\u7801\\u5728\\u6267\\u884c\\u65f6\\u5c06\\u5e26\\u4e0a lodash.js<\\/a> \\u5e93\\u5df2\\u7ecf\\u9ed8\\u8ba4\\u88ab\\u5305\\u542b\\u3002<\\/p>\\r\\n\\r\\n \\u5982\\u9700\\u4f7f\\u7528\\u961f\\u5217\\/\\u4f18\\u5148\\u961f\\u5217\\uff0c\\u60a8\\u53ef\\u4f7f\\u7528 datastructures-js\\/priority-queue@5.3.0<\\/a> \\u548c datastructures-js\\/queue@4.2.1<\\/a>\\u3002<\\/p>\"],\"ruby\":[\"Ruby\",\" \\u4f7f\\u7528 \\u4e00\\u4e9b\\u5e38\\u7528\\u7684\\u6570\\u636e\\u7ed3\\u6784\\u5df2\\u5728 Algorithms \\u6a21\\u5757\\u4e2d\\u63d0\\u4f9b\\uff1ahttps:\\/\\/www.rubydoc.info\\/github\\/kanwei\\/algorithms\\/Algorithms<\\/p>\"],\"swift\":[\"Swift\",\" \\u7248\\u672c\\uff1a \\u6211\\u4eec\\u901a\\u5e38\\u4fdd\\u8bc1\\u66f4\\u65b0\\u5230 Apple\\u653e\\u51fa\\u7684\\u6700\\u65b0\\u7248Swift<\\/a>\\u3002\\u5982\\u679c\\u60a8\\u53d1\\u73b0Swift\\u4e0d\\u662f\\u6700\\u65b0\\u7248\\u7684\\uff0c\\u8bf7\\u8054\\u7cfb\\u6211\\u4eec\\uff01\\u6211\\u4eec\\u5c06\\u5c3d\\u5feb\\u66f4\\u65b0\\u3002<\\/p>\"],\"golang\":[\"Go\",\" \\u7248\\u672c\\uff1a \\u652f\\u6301 https:\\/\\/godoc.org\\/github.com\\/emirpasic\\/gods@v1.18.1<\\/a> \\u7b2c\\u4e09\\u65b9\\u5e93\\u3002<\\/p>\"],\"python3\":[\"Python3\",\" \\u7248\\u672c\\uff1a \\u4e3a\\u4e86\\u65b9\\u4fbf\\u8d77\\u89c1\\uff0c\\u5927\\u90e8\\u5206\\u5e38\\u7528\\u5e93\\u5df2\\u7ecf\\u88ab\\u81ea\\u52a8 \\u5bfc\\u5165\\uff0c\\u5982array<\\/a>, bisect<\\/a>, collections<\\/a>\\u3002 \\u5982\\u679c\\u60a8\\u9700\\u8981\\u4f7f\\u7528\\u5176\\u4ed6\\u5e93\\u51fd\\u6570\\uff0c\\u8bf7\\u81ea\\u884c\\u5bfc\\u5165\\u3002<\\/p>\\r\\n\\r\\n \\u5982\\u9700\\u4f7f\\u7528 Map\\/TreeMap \\u6570\\u636e\\u7ed3\\u6784\\uff0c\\u60a8\\u53ef\\u4f7f\\u7528 sortedcontainers<\\/a> \\u5e93\\u3002<\\/p>\"],\"scala\":[\"Scala\",\" \\u7248\\u672c\\uff1a \\u7248\\u672c\\uff1a \\u6211\\u4eec\\u4f7f\\u7528\\u7684\\u662f JetBrains \\u63d0\\u4f9b\\u7684 experimental compiler\\u3002\\u5982\\u679c\\u60a8\\u8ba4\\u4e3a\\u60a8\\u9047\\u5230\\u4e86\\u7f16\\u8bd1\\u5668\\u76f8\\u5173\\u7684\\u95ee\\u9898\\uff0c\\u8bf7\\u5411\\u6211\\u4eec\\u53cd\\u9988<\\/p>\"],\"rust\":[\"Rust\",\" \\u7248\\u672c\\uff1a \\u652f\\u6301 crates.io \\u7684 rand<\\/a><\\/p>\"],\"php\":[\"PHP\",\" With bcmath module.<\\/p>\"],\"typescript\":[\"TypeScript\",\" TypeScript 5.1.6<\\/p>\\r\\n\\r\\n Compile Options: --alwaysStrict --strictBindCallApply --strictFunctionTypes --target ES2022<\\/p>\\r\\n\\r\\n lodash.js<\\/a> \\u5e93\\u5df2\\u7ecf\\u9ed8\\u8ba4\\u88ab\\u5305\\u542b\\u3002<\\/p>\\r\\n\\r\\n \\u5982\\u9700\\u4f7f\\u7528\\u961f\\u5217\\/\\u4f18\\u5148\\u961f\\u5217\\uff0c\\u60a8\\u53ef\\u4f7f\\u7528 datastructures-js\\/priority-queue@5.3.0<\\/a> \\u548c datastructures-js\\/queue@4.2.1<\\/a>\\u3002<\\/p>\"],\"racket\":[\"Racket\",\"clang 11<\\/code> \\u91c7\\u7528\\u6700\\u65b0C++ 20\\u6807\\u51c6\\u3002<\\/p>\\r\\n\\r\\n
-O2<\\/code>\\u7ea7\\u4f18\\u5316\\u3002AddressSanitizer<\\/a> \\u4e5f\\u88ab\\u5f00\\u542f\\u6765\\u68c0\\u6d4b
out-of-bounds<\\/code>\\u548c
use-after-free<\\/code>\\u9519\\u8bef\\u3002<\\/p>\\r\\n\\r\\n
OpenJDK 17<\\/code>\\u3002\\u53ef\\u4ee5\\u4f7f\\u7528Java 8\\u7684\\u7279\\u6027\\u4f8b\\u5982\\uff0clambda expressions \\u548c stream API\\u3002<\\/p>\\r\\n\\r\\n
Python 2.7.12<\\/code><\\/p>\\r\\n\\r\\n
GCC 8.2<\\/code>\\uff0c\\u91c7\\u7528GNU11\\u6807\\u51c6\\u3002<\\/p>\\r\\n\\r\\n
-O1<\\/code>\\u7ea7\\u4f18\\u5316\\u3002 AddressSanitizer<\\/a>\\u4e5f\\u88ab\\u5f00\\u542f\\u6765\\u68c0\\u6d4b
out-of-bounds<\\/code>\\u548c
use-after-free<\\/code>\\u9519\\u8bef\\u3002<\\/p>\\r\\n\\r\\n
\\r\\nstruct hash_entry {\\r\\n int id; \\/* we'll use this field as the key *\\/\\r\\n char name[10];\\r\\n UT_hash_handle hh; \\/* makes this structure hashable *\\/\\r\\n};\\r\\n\\r\\nstruct hash_entry *users = NULL;\\r\\n\\r\\nvoid add_user(struct hash_entry *s) {\\r\\n HASH_ADD_INT(users, id, s);\\r\\n}\\r\\n<\\/pre>\\r\\n<\\/p>\\r\\n\\r\\n
\\r\\nstruct hash_entry *find_user(int user_id) {\\r\\n struct hash_entry *s;\\r\\n HASH_FIND_INT(users, &user_id, s);\\r\\n return s;\\r\\n}\\r\\n<\\/pre>\\r\\n<\\/p>\\r\\n\\r\\n
\\r\\nvoid delete_user(struct hash_entry *user) {\\r\\n HASH_DEL(users, user); \\r\\n}\\r\\n<\\/pre>\\r\\n<\\/p>\"],\"csharp\":[\"C#\",\"
Node.js 16.13.2<\\/code><\\/p>\\r\\n\\r\\n
--harmony<\\/code> \\u6807\\u8bb0\\u6765\\u5f00\\u542f \\u65b0\\u7248ES6\\u7279\\u6027<\\/a>\\u3002<\\/p>\\r\\n\\r\\n
Ruby 3.1<\\/code>\\u6267\\u884c<\\/p>\\r\\n\\r\\n
Swift 5.5.2<\\/code><\\/p>\\r\\n\\r\\n
Go 1.21<\\/code><\\/p>\\r\\n\\r\\n
Python 3.10<\\/code><\\/p>\\r\\n\\r\\n
Scala 2.13<\\/code><\\/p>\"],\"kotlin\":[\"Kotlin\",\"
Kotlin 1.9.0<\\/code><\\/p>\\r\\n\\r\\n
rust 1.58.1<\\/code><\\/p>\\r\\n\\r\\n
PHP 8.1<\\/code>.<\\/p>\\r\\n\\r\\n