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++ 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 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. |
# 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# 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 |
<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)