I need help to optimise the following code in C++, which implements a queue with two stacks. Unfortunately, it's not passing some of the test cases @ the following link: https://www.hackerrank.com/challenges/ctci-queue-using-two-stacks The (hidden) test cases yield "Terminated due to timeout 2s"
. How can I make my implementation faster?
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
using namespace std;
class MyQueue {
public:
stack<int> stack_newest_on_top, stack_oldest_on_top;
void push(int x) {
/* Check if the stack_oldest_on_top is empty..
if it is not empty, push all the elements onto
stack_newest_on_top */
while(true != stack_oldest_on_top.empty()) {
stack_newest_on_top.push(stack_oldest_on_top.top());
stack_oldest_on_top.pop();
}
/* When you want to push a value on to the que,
it should be stack_newest_on_top*/
stack_newest_on_top.push(x);
}
void pop() {
/* Check if the stack_newest_on_top is empty.. */
while(true != stack_newest_on_top.empty()) {
/* Access the top of the newest stack */
stack_oldest_on_top.push(stack_newest_on_top.top());
/* After acessing the top, just pop it off */
stack_newest_on_top.pop();
}
if (true != stack_oldest_on_top.empty()) {
/* Pop the elem at the top of oldest stack. */
stack_oldest_on_top.pop();
}
}
int front() {
int rt_value = 0;
while(true != stack_newest_on_top.empty()) {
stack_oldest_on_top.push(stack_newest_on_top.top());
/* After acessing the top, just pop it off */
stack_newest_on_top.pop();
}
if (true != stack_oldest_on_top.empty()) {
/* Get the top element of the stack */
rt_value = stack_oldest_on_top.top();
}
return rt_value;
}
};
int main() {
MyQueue q1;
int q, type, x;
cin >> q;
for(int i = 0; i < q; i++) {
cin >> type;
if(type == 1) {
cin >> x;
q1.push(x);
}
else if(type == 2) {
q1.pop();
}
else cout << q1.front() << endl;
}
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
return 0;
}
-
2\$\begingroup\$ To the best of your knowledge, is the problem one of correctness, or of performance? Could you include some of your own test cases in the question? \$\endgroup\$200_success– 200_success2017年03月13日 07:29:20 +00:00Commented Mar 13, 2017 at 7:29
2 Answers 2
Lets assume the following test case: First you push a million elements into the queue. Than you perform alternating a pop and a push. The pop will move all of the million elements of the first stack to the second one and the push will move all of them back to the first time. Every alternating push and pop call has a time complexity of O(size of queue)
. This is not very efficient and you get time problems really soon. And that is why you get the "Terminated due to timeout 2s"
error on Hackerrank.
So copying the elements like crazy is definitely not the way to go. How can you improve it?
Here's a hint: The main error that you do is, that you assume that one of the stacks should be empty at all time. This doesn't have to be the case. Only copy if you really have to.
If you are still stuck, check out the solution:
stack_newest_on_top
keeps the newest elements on top. So if you push one element into the queue, just push it onto this stack. Don't worry about the aboutstack_oldest_on_top
.
If you pop/front an element, do the same thing. Just use the top element fromvoid push(int x) { stack_newest_on_top.push(x); }
stack_oldest_on_top
. Only ifstack_oldest_on_top
is empty. You need to move all the elementsfrom stack_newest_on_top
tostack_oldest_on_top
.
Notice, in the worst case avoid pop() { if (stack_oldest_on_top.empty()) { while (!stack_newest_on_top.empty()) { stack_oldest_on_top.push(stack_newest_on_top.top()); stack_newest_on_top.pop(); } } stack_oldest_on_top.pop(); }
pop
has still O(size of queue) time complexity. But it is called very rarely. In fact every element moves from the first stack only once to the second stack. This gives you an amortised time complexity of O(1).
-
\$\begingroup\$ Thanks a lot for your answer. Yes, it worked. And all the test cases passed @ HackerRank. \$\endgroup\$Venkata Pavan– Venkata Pavan2017年03月14日 09:56:10 +00:00Commented Mar 14, 2017 at 9:56
In addition to the comment of @user38034 I believe there are some additional things to mention: 0. The obvious namespace std; comment. This is bad practice and not needed here.
Why are your two stacks public? They should not be accessible from the outside.
You are not modifying the value of the push argument, so you should mark it const.
Despite this being a challenge, you should still clean your code up, this means no unneeded includes.
You are missing functionality. Even if you pass the tests, you should provide certain standard functionality such as: empty(), size(), clear()
You should avoid multiple declarations on a single line. Disk space is cheap so use it, as it increases readability by a ton.