Amazon Interview Question for Software Engineer in Tests






Comment hidden because of low score. Click to expand.
1
of 1 vote

My option is to implement the queue with a Heap so that max can be easily maintained with enqueue and dequeue operations.

- Anonymous March 09, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

I s'pose it never said that enqueue and dequeue had to be O(1), but it seems like the intent of the question.

- Anonymous March 09, 2010 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

A Queue can be implemented as a pair of back to back stacks. Lets say we have the following elements in the queue : 1 2 3 4 5 6 7 8 9. We can represent this as two stacks P = 1 2 3 4 5 and Q = 6 7 8 9. The top of P is at 1 and the top of Queue is at 9. In an enqueue operation, the element is added into P. While in a dequeue, an element is removed from Q. Every element in P maintains the min when it arrived, and every element in Q maintains the min behind it. Thus finding the min is only going to compare top's min pointers of P and Q and can be found in O(1) time. Each enqueue takes O(1) time as we can enqueue into P and each dequeue takes O(1) time as we can remove from Q. But the problem is, when we do a dequeue operation from Q and we find Q to be empty, we will be required to copy all the elements of P into Q and update corresponding min pointers. This takes O(n) time. But from an amortized perspective, this slow operation is paid by the enqueue operation. By the accounting method, when we insert an element, we spend 3 dollars of charge - 1 for the actual enqueue operation, 1 to get copied into Q (Please note that an element gets copied into Q from P only once) and 1 for the dequeue operation. Hence we have the following running time guarantees -

Enqueue - O(1) Amortized
Dequeue - O(1) Amortized
Min - O(1) Worst case

- Catalan March 14, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Max is the function to find the largest element in Queue.

- Roshan March 09, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Max is the function to find the largest element in Queue.

- Roshan March 09, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Amortized O(1) can be had by maintaining one doubly-linked list for the queue and another for the sequence of queue entries that are larger than those behind them. With this scheme we may have to delete a bunch of crap from list #2 (but everything is inserted at most once, so it's still amortized O(1)).

I have no idea at the moment how to get worst-case O(1).

- Anonymous March 09, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Just maintain the max_next node pointer in each node and adjust the pointer while performing enqueue and dequeue.
Just a pseudo code:

struct node{
     int d;
     node *next;
     node *max_next;};

  node *max_node;
  //its just a pseudo code
  void dequeue()
  {
      tmp=new node;
      if(tmp->d > max_node->data)
      {
           tmp->max_next=max_node;
           max_node=tmp;
       }

Similarly we can write dequeue method.

- Anonymous March 09, 2010 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

If I understand max_next correctly, you have a linked list corresponding to my sequence #2. When a new value is enqueued, it's true that it suffices to update exactly one pointer, but I don't see how to figure out which one in worst-case time o(log #elements_in_linked_list_two).

- Anonymous March 09, 2010 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

One approach is to keep another list of O(n) space apart from the queue and sort it during Enqueue. Dequeue will have to remove the node from the list as well as the queue.
Time Complexity:
O(nLog n) for enqueue due to sorting
O(n) for dequeue due to reordering
O(1) for finding the max

- Anonymous March 10, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

since the constraint does not talk about restrictions on extra data structures, we can use a max heap to keep track of max element in the queue.
Every time u enqueue, heapify - if enque'd element is bigger than other elements , it will float to the root, every time u deque, remove the corresponding element from heap (O(n) for searching it). And anytime u want the max, its the root of the heap (O(1)).
Building heap(while enquing) is n times log n so nlogn.

- game March 11, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Thats good enough. But if everything seems to be O(1) then we need to change gears. Possible solution could be use two queues - even a single queue is doable - with O(1) complexity for all operations.

- hary March 11, 2010 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

My bad the above is not a good idea

- hary March 12, 2010 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

fuck u hary

- Anonymous June 20, 2012 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

One extra element space O(1) for remembering the max element.
If a new element comes - check against max to see if this is the new max. Update max.
If an element goes out, cross check the whole queue to find the new max element. Update max.

Do this make sense?

- becga March 11, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

since on dequeue you are checking the entire queue so looks like its not O(1). Instead i feel the answer posted in the third post by Anonymous looks doable. Moreover, right now it looks that a single Doubly-linked list would do the job and yes it would be O(1) on an amortized basis.

- hary March 12, 2010 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

u can maintain 2 queue one for maxele and normal ele
operations in first queue (contains all elements){
normal enqueue and normal dequeue;
}
operations in second queue {
enqueue : whenever u enqueue in first queue and if element in front of this queue is smaller then element beeing inserted...(insert the element at first in second queue other wise dont insert)
dequeue : whenever u dequeue in first queue and if element removed from first queue is equal to first element in second queue then remove element from this queue too...
}

idea is whenever we insert in oringal queue we are maintianing list of max in another queue so tat we need not change the structure of node... rather then single max maintained by becga...

- Anonymous March 12, 2010 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Ok... let me be precise here.

All operations should generate O(1) complexity.

That was the question.

- Roshan March 15, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 2 vote

Solution is pretty simple. We ourself make things complex by not looking at the simple side of it.

1.) Doubly linked list for queue.
2.) Keep max along with each node till that node.

Let say the queue is
2 ->8 ->6 ->9

struct{
int data
int max
struct * next
struct *prev
}

when 2 inserted, queue will be
(2,2)
when 8 inserted, queue will be
(2,2) -> (8,8)
when 6 inserted, queue will be
(2,2) -> (8,8) -> (6, 8)
when 9 inserted, queue will be
(2,2) -> (8,8) -> (6, 8) -> (9,9)

Here all operations are O(1)

- dce.sunil March 17, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

sounds correct to me

- Anonymous March 26, 2010 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

Try with 10->6->8->7->12->8
so you will find (10,10)->(6,10)->(8,10)->(7,10)->(12,12)->(8,12)

So, when you dequeue 10 from the queue you have to update all the lists until you reach to a node whose value is greater than or equal to 10 i.e. 12.

- Psycho September 25, 2012 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

my idea is to use a priority queue, ie a heap, in fact a max heap. a max heap is a tree like structure where the root of the tree (heap) is the maximum element.

so for example a heap (nothing but a complete binary tree except lower level) is like this

55
50 45
18 35 40 39
17

50 and 45 children of 55
18 35 children of 50
40 39 children of 45
17 child of 18

if you see the tree, it is completely filled except the bottom level (which is nothing but a heap, in this case a max heap with the maximum element at root)

Now simply do an array implementation
the array would be 55 50 45 18 35 40 39 17
max element---is arr[0]
dequeue---remove first element and check for the next biggest element. This is not that difficult...remember percolate down approach
enqueue is always done at the end of the array but again maintaining heap structure and order property

I think what the interviewer wants boggles down to implementation of a max priority queue i.e a max heap

- veerun14 March 17, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

This is simple. Every time u enQ, check max value. If greater, update max value. Else, dont change max. U can get max element in just O(1). Space is O(1) for the max element.

- Helper April 08, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

You are a genius! No wonder no one else came up with this solution... rest are fools.

- Anonymous April 08, 2010 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

If I dequeue an element , then max value might also get changed. So it wont work if i dequeue elements

- Zee August 21, 2012 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

@helper: if u maintain just the max value, if u dequeue it then what will be the max value? so I think max heap is the best solution

- Anonymous April 25, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

why not a stack for the maintaining the max values?

- Anonymous April 28, 2010 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

There are two possible approaches..

1)By maintaining a max_next node pointer that would store the maximum value of the nodes below it. This value is updated upon enqueue depending on the value of the node enqueued. This takes O(1) time.

Cons: If there is a large volume of data, this may be inefficient because we might have to store a pointer for each node - causes redundancy.

To overcome this, if we are allowed additional storage, then we could go in for an alternate solution.

2) Use another data structure Stack. Every time a node is enqueued, check its value with the value of the node in the Stack. If it is greater, then push this node into the stack. If the value is lesser, then do nothing. To find the maximum element, just do a pop from the stack and that would return the maximum value. This operation takes O(1) time.

- Anonymous April 30, 2010 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

both of your approaches share the same idea. but I guess it doesn't work.
like approach 2.
what if the element with max value is dequeued? you will pop the max from stack as well, then what? how will you find the next max? do you mean the next max will be the next top element in the stack?
no, the next top element in the stack is enqueued before the max element you just popped out.so it's already gone before, this element is no longer in the queue.
let me know if i misunderstood your idea

- Jovi June 06, 2010 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

i think this should work

maintain a doubly link list for max numbers.

while inserting a number in queue ,if it is greater than the current max insert it at head of the DLL. and maintain a pointer from the node in queue to this node in DLL

while deque, if the number to be dequed has a pointer to a node in max DLL delete the node from DLL ( can be done in O(1) as it is a DLL and pointer to the node is known) and deque the number.

max at any point is the number at head of DLL.

- Anonymous July 19, 2010 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

The extra stack and extra Q think wont work.
Consider the Queue:

-10 -30 -20
front rear

If you have a Stack and add elements to it if they are greater than present MAX
then STack would have -10 ONLY.
Now after dequeue, the largest element is -20 and its not in that Stack.
Neither the Queue would work.
I think use a MAX HEAP or use a priority Queue.
Logically every element in the given Queue is a contender to become the MAX. So insert each element in a decreasing priority Queue. Now the MAX operation would be O(1) because you need to dequeue the priority queue just once :)

However the enqueue/dequeue operations would be cumbersome!

- Prateek June 21, 2011 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

<pre lang="" line="1" title="CodeMonkey43615" class="run-this">/*This is a running code. Just dont try to overflow buffers here. Very primitive
error correction mechanisms. The front of queue points to one element BEFORE actual
front. Rear points to rear elements.
Code works. Except when you empty the max queue. So try to be reasonable.
*/

#include <stdio.h>
#define MAXQ 100
typedef struct{
int items[MAXQ];
int front;
int rear;
}queue;

void enqueue(queue *pq, int val);
void dequeue(queue *pq, int *val);


int main(){
queue mainq, maxq;
mainq.front=mainq.rear=maxq.front=maxq.rear=0;
int choice,val;
int temp;
int first=1;
while(1){
printf("\n1. Enqueue \n2. Dequeue\n3. Maximum Element\n");
scanf("%d",&choice);
switch (choice)
{
case 1:
scanf("%d",&val);
enqueue(&mainq,val);
if(first)
{
enqueue(&maxq,val);
first=0;
}
else if (maxq.front!=maxq.rear) {
if(maxq.items[maxq.front + 1]<val)
maxq.items[maxq.front + 1] = val;
else
{while(1)
{
temp=maxq.items[maxq.rear];
if(temp<=val)
{maxq.items[(maxq.rear)--];}
else
{
enqueue(&maxq,val);
break;}
}
}}
break;
case 2:
dequeue(&mainq,&val);
if(val==maxq.items[maxq.front + 1])
dequeue(&maxq,&temp);
break;

case 3:
printf("\n\nMAX IS: %d ", maxq.items[maxq.front + 1]);

}

}
}

void enqueue(queue *pq, int val){
if (pq->rear==(MAXQ-1))
{pq->rear=0;}
else
(pq->rear)++;
if(pq->rear==pq->front)
{printf("\nOverflow!");
if(pq->rear)
(pq->rear)--;
else
pq->rear=MAXQ-1;
//printf("\nFRONT: %d REAR: %d",pq->front,pq->rear);
}
else
{pq->items[pq->rear]=val;
//printf("\nFRONT: %d REAR: %d",pq->front,pq->rear);
}


}

void dequeue(queue *pq, int *val){
if(pq->front==pq->rear) {
printf("\nUndeflow!");}
else
if(pq->front==MAXQ-1) {(pq->front)=0;}
else{
(pq->front)++;
*val=pq->items[pq->front];
//printf("\nFRONT: %d REAR: %d",pq->front,pq->rear);

}
}
</pre><pre title="CodeMonkey43615" input="yes">
</pre>

- Anonymous June 21, 2011 | Flag Reply


Add a Comment
Name:

Writing Code? Surround your code with {{{ and }}} to preserve whitespace.

Books

is a comprehensive book on getting a job at a top tech company, while focuses on dev interviews and does this for PMs.

Learn More

Videos

CareerCup's interview videos give you a real-life look at technical interviews. In these unscripted videos, watch how other candidates handle tough questions and how the interviewer thinks about their performance.

Learn More

Resume Review

Most engineers make critical mistakes on their resumes -- we can fix your resume with our custom resume review service. And, we use fellow engineers as our resume reviewers, so you can be sure that we "get" what you're saying.

Learn More

Mock Interviews

Our Mock Interviews will be conducted "in character" just like a real interview, and can focus on whatever topics you want. All our interviewers have worked for Microsoft, Google or Amazon, you know you'll get a true-to-life experience.

Learn More