Implement Undo and Redo features of a Text Editor
Given an array of strings Q[], consisting of queries of the following types:
- “WRITE 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”: Reads and prints the contents of the documents.
Examples:
Input: Q = {“WRITE A”, “WRITE B”, “WRITE C”, “UNDO”, “READ”, “REDO”, “READ”}
Output: AB ABC
Explanation:
Perform “WRITE A” on the document. Therefore, the document contains only “A”.
Perform “WRITE B” on the document. Therefore, the document contains “AB”.
Perform “WRITE C” on the document. Therefore, the document contains “ABC”.
Perform “UNDO” on the document. Therefore, the document contains “AB”.
Print the contents of the document, i.e. “AB”
Perform “REDO” on the document. Therefore, the document contains “ABC”.
Print the contents of the document, i.e. “ABC”Input: Q = {“WRITE x”, “WRITE y”, “UNDO”, “WRITE z”, “READ”, “REDO”, “READ”}
Output:xz xzy
Approach: The problem can be solved using Stack. Follow the steps below to solve the problem:
- Initialize two stacks, say Undo and Redo.
- Traverse the array of strings, Q, and perform the following operations:
- If “WRITE” string is encountered, push the character to Undo stack
- If “UNDO” string is encountered, pop the top element from Undo stack and push it to Redo stack.
- If “REDO” string is encountered, pop the top element of Redo stack and push it into the Undo stack.
- If “READ” string is encountered, print all the elements of the Undo stack in reverse order.
Below is the implementation of the above approach:
C++
// C++ Program to implement // the above approach #include <bits/stdc++.h> using namespace std; // Function to perform // "WRITE X" operation void WRITE(stack< char >& Undo, char X) { // Push an element to // the top of stack Undo.push(X); } // Function to perform // "UNDO" operation void UNDO(stack< char >& Undo, stack< char >& Redo) { // Stores top element // of the stack char X = Undo.top(); // Erase top element // of the stack Undo.pop(); // Push an element to // the top of stack Redo.push(X); } // Function to perform // "REDO" operation void REDO(stack< char >& Undo, stack< char >& Redo) { // Stores the top element // of the stack char X = Redo.top(); // Erase the top element // of the stack Redo.pop(); // Push an element to // the top of the stack Undo.push(X); } // Function to perform // "READ" operation void READ(stack< char > Undo) { // Store elements of stack // in reverse order stack< char > revOrder; // Traverse Undo stack while (!Undo.empty()) { // Push an element to // the top of stack revOrder.push(Undo.top()); // Erase top element // of stack Undo.pop(); } while (!revOrder.empty()) { // Print the top element // of the stack cout << revOrder.top(); Undo.push(revOrder.top()); // Erase the top element // of the stack revOrder.pop(); } cout << " " ; } // Function to perform the // queries on the document void QUERY(vector<string> Q) { // Stores the history of all // the queries that have been // processed on the document stack< char > Undo; // Stores the elements // of REDO query stack< char > Redo; // Stores total count // of queries int N = Q.size(); // Traverse all the query for ( int i = 0; i < N; i++) { if (Q[i] == "UNDO" ) { UNDO(Undo, Redo); } else if (Q[i] == "REDO" ) { REDO(Undo, Redo); } else if (Q[i] == "READ" ) { READ(Undo); } else { WRITE(Undo, Q[i][6]); } } } // Driver Code int main() { vector<string> Q = { "WRITE A" , "WRITE B" , "WRITE C" , "UNDO" , "READ" , "REDO" , "READ" }; QUERY(Q); return 0; } |
Java
// Java Program to implement the above approach import java.util.*; public class Main { // Stores the history of all // the queries that have been // processed on the document static Stack<Character> Undo = new Stack<Character>(); // Stores the elements // of REDO query static Stack<Character> Redo = new Stack<Character>(); // Function to perform // "WRITE X" operation static void WRITE(Stack<Character> Undo, char X) { // Push an element to // the top of stack Undo.push(X); } // Function to perform // "UNDO" operation static void UNDO(Stack<Character> Undo, Stack<Character> Redo) { // Stores top element // of the stack char X = ( char )Undo.peek(); // Erase top element // of the stack Undo.pop(); // Push an element to // the top of stack Redo.push(X); } // Function to perform // "REDO" operation static void REDO(Stack<Character> Undo, Stack<Character> Redo) { // Stores the top element // of the stack char X = ( char )Redo.peek(); // Erase the top element // of the stack Redo.pop(); // Push an element to // the top of the stack Undo.push(X); } // Function to perform // "READ" operation static void READ(Stack<Character> Undo) { // Store elements of stack // in reverse order Stack<Character> revOrder = new Stack<Character>(); // Traverse Undo stack while (Undo.size() > 0 ) { // Push an element to // the top of stack revOrder.push(Undo.peek()); // Erase top element // of stack Undo.pop(); } while (revOrder.size() > 0 ) { // Print the top element // of the stack System.out.print(revOrder.peek()); Undo.push(revOrder.peek()); // Erase the top element // of the stack revOrder.pop(); } System.out.print( " " ); } // Function to perform the // queries on the document static void QUERY(String[] Q) { // Stores total count // of queries int N = Q.length; // Traverse all the query for ( int i = 0 ; i < N; i++) { if (Q[i] == "UNDO" ) { UNDO(Undo, Redo); } else if (Q[i] == "REDO" ) { REDO(Undo, Redo); } else if (Q[i] == "READ" ) { READ(Undo); } else { WRITE(Undo, Q[i].charAt( 6 )); } } } public static void main(String[] args) { String[] Q = { "WRITE A" , "WRITE B" , "WRITE C" , "UNDO" , "READ" , "REDO" , "READ" }; QUERY(Q); } } // This code is contributed by divyeshrabadiya07. |
Python3
# Python Program to implement # the above approach global Undo global Redo # Stores the history of all # the queries that have been # processed on the document Undo = [] # Stores the elements # of REDO query Redo = [] # Function to perform # "WRITE X" operation def WRITE(Undo, X): # Push an element to # the top of stack Undo.append(X) # Function to perform # "UNDO" operation def UNDO(Undo, Redo): # Stores top element # of the stack X = Undo[ - 1 ] # Erase top element # of the stack Undo.pop() # Push an element to # the top of stack Redo.append(X) # Function to perform # "REDO" operation def REDO(Undo, Redo): # Stores the top element # of the stack X = Redo[ - 1 ] # Erase the top element # of the stack Redo.pop() # Push an element to # the top of the stack Undo.append(X) # Function to perform # "READ" operation def READ(Undo): print ( * Undo, sep = "", end = " " ) # Function to perform the # queries on the document def QUERY(Q): # Stores total count # of queries N = len (Q) # Traverse all the query for i in range (N): if (Q[i] = = "UNDO" ): UNDO(Undo, Redo) elif (Q[i] = = "REDO" ): REDO(Undo, Redo) elif (Q[i] = = "READ" ): READ(Undo) else : WRITE(Undo, Q[i][ 6 ]) # Driver Code Q = [ "WRITE A" , "WRITE B" , "WRITE C" , "UNDO" , "READ" , "REDO" , "READ" ] QUERY(Q) #This code is contributed by avanitrachhadiya2155 |
C#
// C# Program to implement the above approach using System; using System.Collections; class GFG { // Stores the history of all // the queries that have been // processed on the document static Stack Undo = new Stack(); // Stores the elements // of REDO query static Stack Redo = new Stack(); // Function to perform // "WRITE X" operation static void WRITE(Stack Undo, char X) { // Push an element to // the top of stack Undo.Push(X); } // Function to perform // "UNDO" operation static void UNDO(Stack Undo, Stack Redo) { // Stores top element // of the stack char X = ( char )Undo.Peek(); // Erase top element // of the stack Undo.Pop(); // Push an element to // the top of stack Redo.Push(X); } // Function to perform // "REDO" operation static void REDO(Stack Undo, Stack Redo) { // Stores the top element // of the stack char X = ( char )Redo.Peek(); // Erase the top element // of the stack Redo.Pop(); // Push an element to // the top of the stack Undo.Push(X); } // Function to perform // "READ" operation static void READ(Stack Undo) { // Store elements of stack // in reverse order Stack revOrder = new Stack(); // Traverse Undo stack while (Undo.Count > 0) { // Push an element to // the top of stack revOrder.Push(Undo.Peek()); // Erase top element // of stack Undo.Pop(); } while (revOrder.Count > 0) { // Print the top element // of the stack Console.Write(revOrder.Peek()); Undo.Push(revOrder.Peek()); // Erase the top element // of the stack revOrder.Pop(); } Console.Write( " " ); } // Function to perform the // queries on the document static void QUERY( string [] Q) { // Stores total count // of queries int N = Q.Length; // Traverse all the query for ( int i = 0; i < N; i++) { if (Q[i] == "UNDO" ) { UNDO(Undo, Redo); } else if (Q[i] == "REDO" ) { REDO(Undo, Redo); } else if (Q[i] == "READ" ) { READ(Undo); } else { WRITE(Undo, Q[i][6]); } } } static void Main() { string [] Q = { "WRITE A" , "WRITE B" , "WRITE C" , "UNDO" , "READ" , "REDO" , "READ" }; QUERY(Q); } } // This code is contributed by rameshtravel07 |
Javascript
<script> // Javascript Program to implement the above approach // Stores the history of all // the queries that have been // processed on the document let Undo = []; // Stores the elements // of REDO query let Redo = []; // Function to perform // "WRITE X" operation function WRITE(Undo, X) { // Push an element to // the top of stack Undo.push(X) } // Function to perform // "UNDO" operation function UNDO(Undo, Redo) { // Stores top element // of the stack let X = Undo[Undo.length - 1]; // Erase top element // of the stack Undo.pop(); // Push an element to // the top of stack Redo.push(X); } // Function to perform // "REDO" operation function REDO(Undo, Redo) { // Stores the top element // of the stack let X = Redo[Redo.length - 1]; // Erase the top element // of the stack Redo.pop(); // Push an element to // the top of the stack Undo.push(X); } // Function to perform // "READ" operation function READ(Undo) { // Store elements of stack // in reverse order let revOrder = []; // Traverse Undo stack while (Undo.length > 0) { // Push an element to // the top of stack revOrder.push(Undo[Undo.length - 1]); // Erase top element // of stack Undo.pop(); } while (revOrder.length > 0) { // Print the top element // of the stack document.write(revOrder[revOrder.length - 1]); Undo.push(revOrder[revOrder.length - 1]); // Erase the top element // of the stack revOrder.pop(); } document.write( " " ); } // Function to perform the // queries on the document function QUERY(Q) { // Stores total count // of queries N = Q.length // Traverse all the query for (let i = 0; i < N; i++) { if (Q[i] == "UNDO" ) { UNDO(Undo, Redo); } else if (Q[i] == "REDO" ) { REDO(Undo, Redo); } else if (Q[i] == "READ" ) { READ(Undo); } else { WRITE(Undo, Q[i][6]); } } } let Q = [ "WRITE A" , "WRITE B" , "WRITE C" , "UNDO" , "READ" , "REDO" , "READ" ]; QUERY(Q); // This code is contributed by suresh07. </script> |
AB ABC
Time Complexity:
UNDO: O(1)
REDO: O(1)
WRITE: O(1)
READ: (N), where N denotes the size of the Undo stack
Auxiliary Space: O(N)
Please Login to comment...