Given an array arr[], consisting of operation of the following types:
- append('X') : Write a character X into the document.
- undo() : Erases the last change made to the document.
- redo(): Restores the most recent undo() operation performed on the document.
- read() : Return the contents of the current documents.
Examples:
Input: arr[] = [append('A'), append('B'), append('C'), undo(), read(), redo(), read()]
Output: [AB, ABC]
Explanation:
Perform append('A') on the document. Therefore, the document contains only “A”.
Perform append('B') on the document. Therefore, the document contains “AB”.
Perform append('C') on the document. Therefore, the document contains “ABC”.
Perform undo() on the document. Therefore, the document contains “AB”.
Perform read() on the document. Return the contents of the document, i.e. “AB”
Perform redo() on the document. Therefore, the document contains “ABC”.
Perform read() on the document. Return the contents of the document, i.e. “ABC”
[Approach] Using Stack - O(n) Time and O(n) Space
The idea is to maintain the character whenever we perform an undo(). Remove the last character from the current string and push it onto the stack (redo). The stack stores characters in the order they were undo the last undo character is on top. When performing a redo(), pop the top character from the redo stack and append it back to the current string.
Whenever a new character is written, the redo stack is cleared because previous undo characters are no longer valid.
Note: In Java and C#, the String class is immutable, meaning once a string object is created, its value cannot be changed. To solve this, we use StringBuilder.
#include <iostream>
#include <stack>
#include <string>
using namespace std;
string doc = "";
stack<char> redost;
// append operation
void append(char X) {
doc.push_back(X);
// clear redo stack on new write
while (!redost.empty()) redost.pop();
}
// undo operation
void undo() {
if (!doc.empty()) {
char last = doc.back();
doc.pop_back();
redost.push(last);
}
}
// redo operation
void redo() {
if (!redost.empty()) {
char ch = redost.top();
redost.pop();
doc.push_back(ch);
}
}
// read operation
string read() {
return doc;
}
int main() {
append('A');
append('B');
append('C');
undo();
cout<<read()<<" ";
redo();
cout<<read()<<" ";
return 0;
}
import java.util.Stack;
class GfG {
static StringBuilder doc = new StringBuilder();
static Stack<Character> redost = new Stack<>();
// append operation
static void append(char X) {
doc.append(X);
// clear redo stack on new write
redost.clear();
}
// undo operation
static void undo() {
if (doc.length() > 0) {
char last = doc.charAt(doc.length() - 1);
doc.deleteCharAt(doc.length() - 1);
redost.push(last);
}
}
// redo operation
static void redo() {
if (!redost.isEmpty()) {
char ch = redost.pop();
doc.append(ch);
}
}
// read operation
static String read() {
return doc.toString();
}
public static void main(String[] args) {
append('A');
append('B');
append('C');
undo();
System.out.print(read() + " ");
redo();
System.out.print(read() +" ");
}
}
doc = ""
redost = []
# append operation
def append(X):
global doc, redost
doc += X
redost.clear()
# undo operation
def undo():
global doc, redost
if doc:
last = doc[-1]
doc = doc[:-1]
redost.append(last)
# redo operation
def redo():
global doc, redost
if redost:
ch = redost.pop()
doc += ch
# read operation
def read():
global doc
return doc
if __name__ == "__main__":
append('A')
append('B')
append('C')
undo()
print(read(), end = " ")
redo()
print(read(), end = " ")
using System;
using System.Collections.Generic;
class GfG {
static string doc = "";
static Stack<char> redost = new Stack<char>();
// append operation
static void append(char x)
{
doc += x;
// clear redo stack on new write
redost.Clear();
}
// undo operation
static void undo()
{
if (doc.Length > 0)
{
char last = doc[doc.Length - 1];
doc = doc.Substring(0, doc.Length - 1);
redost.Push(last);
}
}
// redo operation
static void redo()
{
if (redost.Count > 0)
{
char ch = redost.Pop();
doc += ch;
}
}
// read operation
static string read()
{
return doc;
}
static void Main(string[] args)
{
append('A');
append('B');
append('C');
undo();
Console.Write(read() + " ");
redo();
Console.Write(read());
}
}
// Global variables
let doc = "";
let redost = [];
// append operation
function append(x) {
doc += x;
// clear redo stack on new write
redost = [];
}
// undo operation
function undo() {
if (doc.length > 0) {
let last = doc[doc.length - 1];
doc = doc.slice(0, -1);
redost.push(last);
}
}
// redo operation
function redo() {
if (redost.length > 0) {
let ch = redost.pop();
doc += ch;
}
}
// read operation
function read() {
return doc;
}
// Driver Code
append('A');
append('B');
append('C');
undo();
let output = [];
output.push(read());
redo();
output.push(read());
console.log(output.join(" "));
Output
AB ABC