Implementing queue using stack - algorithm

This is question from homework:
Implement a FIFO queue using two stacks.
The total running time of Enqueue and Dequeue functions should be O(n) in the worst case scenario. Also, analyze the running time of the algorithm.
What I did:
void Enqueue(T *value)
{
s1.Push(value);
}
T *Dequeue()
{
if (s2.size > 0)
return s2.Pop();
else if (s1.size > 0)
{
for (int i = 0; i < s1.size; i++)
s2.Push(s1.Pop());
return s2.Pop();
}
else return NULL;
}
Analysis of the algorithm:
Running time of one Enqueue is Theta(1). Total running time of the all Enqueue functions is n * Theta(1) = Theta(n).
Running time of Dequeue in worst case scenario is Theta(n) (when you call it after the last Enqueue, i.e. when all the items inserted). In all other cases the running time is Theta(1).
So, the total running time is:
O(n) + O(n) + n * O(1) = 3 * O(n) = O(n)
Is this correct?

So, the total running time is: O(n) + O(n) + n * O(1) = 3 * O(n) =
O(n)
You're in the right direction, but you usually don't analyze "total running time", you split it to amortized average, worst case, and best case - and analyze it for each operation.
In your algorithm, it is easy to see that:
enqueue() runs in Theta(1) for all cases.
dequeue() runs in Theta(n) worst case and Theta(1) best case.
Noe, for the tricky part - we need to analyzed dequeue() amortised analysis.
First, note that before each Theta(n) (worst case), dequeue() you must have emptied the list, and inserted n elements.
This means, in order for the worst case to happen, you must have done at least n enqueue() operations, each Theta(1).
This gives us amortised time of:
T(n) = (n*CONST1 + CONST2*n) /(n+1)
^ ^ ^
n enqueues 1 "espansive" dequeue #operations
It is easy to see that T(n) is in Theta(1), giving you Theta(1) amortized time complexity.
tl;dr:
enqueue: Theta(1) all cases
dequeue: Theta(1) amortized, Theta(n) worst case

import java.util.Stack;
public class Q5_ImplementQueueUsingStack {
/**
* #param args
* Implement a MyQueue class which implements a queue using two stacks.
*/
public static Stack<Integer> s1 = new Stack<Integer>();
public static Stack<Integer> s2 = new Stack<Integer>();
public static void main(String[] args) {
int[] array = {2,5,10,3,11,7,13,8,9,4,1,6};
for(int i=0;i<5;i++){
enQueue(array[i]);
}
System.out.println(deQueue());
System.out.println(deQueue());
System.out.println(deQueue());
System.out.println(deQueue());
System.out.println(deQueue());
for(int i=0;i<4;i++){
enQueue(array[i+5]);
}
System.out.println(deQueue());
for(int i=0;i<3;i++){
enQueue(array[i+9]);
}
System.out.println(deQueue());
System.out.println(deQueue());
System.out.println(deQueue());
System.out.println(deQueue());
System.out.println(deQueue());
System.out.println(deQueue());
}
public static void enQueue(int data){
s1.push(data);
}
public static int deQueue(){
if(s2.isEmpty())
while(!s1.isEmpty())
s2.push(s1.pop());
return s2.pop();
}
}

Implement the following operations of a queue using stacks.
push(x) -- Push element x to the back of queue.
pop() -- Removes the element from in front of queue.
peek() -- Get the front element.
empty() -- Return whether the queue is empty.
class MyQueue {
Stack<Integer> input;
Stack<Integer> output;
/** Initialize your data structure here. */
public MyQueue() {
input = new Stack<Integer>();
output = new Stack<Integer>();
}
/** Push element x to the back of queue. */
public void push(int x) {
input.push(x);
}
/** Removes the element from in front of queue and returns that element. */
public int pop() {
peek();
return output.pop();
}
/** Get the front element. */
public int peek() {
if(output.isEmpty()) {
while(!input.isEmpty()) {
output.push(input.pop());
}
}
return output.peek();
}
/** Returns whether the queue is empty. */
public boolean empty() {
return input.isEmpty() && output.isEmpty();
}
}

Related

Last remaining number

I was asked this question in an interview.
Given an array 'arr' of positive integers and a starting index 'k' of the array. Delete element at k and jump arr[k] steps in the array in circular fashion. Do this repeatedly until only one element remain. Find the last remaining element.
I thought of O(nlogn) solution using ordered map. Is any O(n) solution possible?
My guess is that there is not an O(n) solution to this problem based on the fact that it seems to involve doing something that is impossible. The obvious thing you would need to solve this problem in linear time is a data structure like an array that exposes two operations on an ordered collection of values:
O(1) order-preserving deletes from the data structure.
O(1) lookups of the nth undeleted item in the data structure.
However, such a data structure has been formally proven to not exist; see "Optimal Algorithms for List Indexing and Subset Rank" and its citations. It is not a proof to say that if the natural way to solve some problem involves using a data structure that is impossible, the problem itself is probably impossible, but such an intuition is often correct.
Anyway there are lots of ways to do this in O(n log n). Below is an implementation of maintaining a tree of undeleted ranges in the array. GetIndex() below returns an index into the original array given a zero-based index into the array if items had been deleted from it. Such a tree is not self-balancing so will have O(n) operations in the worst case but in the average case Delete and GetIndex will be O(log n).
namespace CircleGame
{
class Program
{
class ArrayDeletes
{
private class UndeletedRange
{
private int _size;
private int _index;
private UndeletedRange _left;
private UndeletedRange _right;
public UndeletedRange(int i, int sz)
{
_index = i;
_size = sz;
}
public bool IsLeaf()
{
return _left == null && _right == null;
}
public int Size()
{
return _size;
}
public void Delete(int i)
{
if (i >= _size)
throw new IndexOutOfRangeException();
if (! IsLeaf())
{
int left_range = _left._size;
if (i < left_range)
_left.Delete(i);
else
_right.Delete(i - left_range);
_size--;
return;
}
if (i == _size - 1)
{
_size--; // Can delete the last item in a range by decremnting its size
return;
}
if (i == 0) // Can delete the first item in a range by incrementing the index
{
_index++;
_size--;
return;
}
_left = new UndeletedRange(_index, i);
int right_index = i + 1;
_right = new UndeletedRange(_index + right_index, _size - right_index);
_size--;
_index = -1; // the index field of a non-leaf is no longer necessarily valid.
}
public int GetIndex(int i)
{
if (i >= _size)
throw new IndexOutOfRangeException();
if (IsLeaf())
return _index + i;
int left_range = _left._size;
if (i < left_range)
return _left.GetIndex(i);
else
return _right.GetIndex(i - left_range);
}
}
private UndeletedRange _root;
public ArrayDeletes(int n)
{
_root = new UndeletedRange(0, n);
}
public void Delete(int i)
{
_root.Delete(i);
}
public int GetIndex(int indexRelativeToDeletes )
{
return _root.GetIndex(indexRelativeToDeletes);
}
public int Size()
{
return _root.Size();
}
}
static int CircleGame( int[] array, int k )
{
var ary_deletes = new ArrayDeletes(array.Length);
while (ary_deletes.Size() > 1)
{
int next_step = array[ary_deletes.GetIndex(k)];
ary_deletes.Delete(k);
k = (k + next_step - 1) % ary_deletes.Size();
}
return array[ary_deletes.GetIndex(0)];
}
static void Main(string[] args)
{
var array = new int[] { 5,4,3,2,1 };
int last_remaining = CircleGame(array, 2); // third element, this call is zero-based...
}
}
}
Also note that if the values in the array are known to be bounded such that they are always less than some m less than n, there are lots of O(nm) algorithms -- for example, just using a circular linked list.
I couldn't think of an O(n) solution. However, we could have O(n log n) average time by using a treap or an augmented BST with a value in each node for the size of its subtree. The treap enables us to find and remove the kth entry in O(log n) average time.
For example, A = [1, 2, 3, 4] and k = 3 (as Sumit reminded me in the comments, use the array indexes as values in the tree since those are ordered):
2(0.9)
/ \
1(0.81) 4(0.82)
/
3(0.76)
Find and remove 3rd element. Start at 2 with size = 2 (including the left subtree). Go right. Left subtree is size 1, which together makes 3, so we found the 3rd element. Remove:
2(0.9)
/ \
1(0.81) 4(0.82)
Now we're starting on the third element in an array with n - 1 = 3 elements and looking for the 3rd element from there. We'll use zero-indexing to correlate with our modular arithmetic, so the third element in modulus 3 would be 2 and 2 + 3 = 5 mod 3 = 2, the second element. We find it immediately since the root with its left subtree is size 2. Remove:
4(0.82)
/
1(0.81)
Now we're starting on the second element in modulus 2, so 1, and we're adding 2. 3 mod 2 is 1. Removing the first element we are left with 4 as the last element.

What is the time complexity of below recursive functions

Below program is to find all the subsets of an array. Is time complexity of the program is O(2^n)?
Is there any easy way to find the time complexity of recursive function?
Thanks in anticipation
public static void getAllSubSet(int[] arr,int[] subset,int index){
if(index == arr.length)
printarr(subset);
else{
subset[index] = -1;
getAllSubSet(arr, subset, index+1);
subset[index] = arr[index];
getAllSubSet(arr, subset, index+1);
}
}
public static void printarr(int[] set){
for(int i=0;i<set.length;i++){
if(set[i] != -1){
System.out.print(set[i] +" ");
}
}
System.out.println("");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = {1,2,3};
int[] subset = new int[arr.length];
getAllSubSet(arr, subset, 0);
}
Answer to your first question:
The complexity of your function is O(n* 2^n). However if n is very large, you can neglect n.
Answer to your second question:
One of the best ways I find for approximating the complexity of the recursive algorithm is drawing the recursion tree. Once you have the recursive tree, you can find the complexity.

Finding the Space Complexitiy for these methods

I'm familiar with running time for both of the following methods which is O(N). However, I'm not familiar with space complexity. Since these methods consists simply of assignment statements, comparison statements, and loops, I assume that the space complexity is just O(1), but want to make sure. Thank you.
//first method
public static <E> Node<E> buildList(E[] items) {
Node<E> head = null;
if (items!=null && items.length>0) {
head = new Node<E> (items[0], null);
Node<E> tail = head;
for (int i=1; i<items.length; i++) {
tail.next = new Node<E>(items[i], null);
tail = tail.next;
}
}
return head;
}
//second method
public static <E> int getLength(Node<E> head) {
int length = 0;
Node<E> node = head;
while (node!=null) {
length++;
node = node.next;
}
return length;
}
As described in this post, space complexity is related to the amount of memory used by the algorithm, depending on the size of the input.
For instance an algorithm with O(1) space complexity uses a fixed amount of memory, independently of the input size. This is the case of your second algorithm that basically only uses a few extra variables.
An algorithm with O(n) space complexity uses an amount of memory proportional to its input size. This is the case of your first algorithm that performs one allocation (one new) for each element of the input.

How to validate if a B-tree is sorted

I just had this as an interview question and was wondering if anyone knows the answer?
Write a method that validates whether a B-tree is correctly sorted. You do NOT need to validate whether
the tree is balanced. Use the following model for a node in the B-tree.
It was to be done in Java and use this model:
class Node {
List<Integer> keys;
List<Node> children;
}
One (space-inefficient but simple) way to do this is to do a generalized inorder traversal of the B-tree to get back the keys in what should be sorted order, then to check whether that sequence actually is in sorted order. Here's some quick code for this:
public static boolean isSorted(Node root) {
ArrayList<Integer> values = new ArrayList<Integer>();
performInorderTraversal(root, values);
return isArraySorted(values);
}
private static void performInorderTraversal(Node root, ArrayList<Integer> result) {
/* An empty tree has no values. */
if (result == null) return;
/* Process the first tree here, then loop, processing the interleaved
* keys and trees.
*/
performInorderTraversal(root.children.get(0), result);
for (int i = 1; i < root.children.size(); i++) {
result.add(root.children.get(i - 1));
performInorderTraversal(root.children.get(i), result);
}
}
private static boolean isArraySorted(ArrayList<Integer> array) {
for (int i = 0; i < array.size() - 1; i++) {
if (array.get(i) >= array.get(i + 1)) return false;
}
return true;
}
This takes time O(n) and uses space O(n), where n is the number of elements in the B-tree. You can cut the space usage down to O(h), where h is the height of the B-tree, by not storing all the elements in the traversal and instead just tracking the very last one, stopping the search early if the next-encountered value is not larger than the previous one. I didn't do that here because it takes more code, but conceptually it's not too hard.
Hope this helps!

Keeping track of the median of an expanding array

Interview Question:
Edited Below
You are given an array. You make 2 heaps out of it, one minheap and the other max heap. Now find the median of the array using these 2 provided heaps in O(nlog n) time.
Corrected Question
Numbers are randomly generated and stored into an (expanding) array. How would you keep track of the median?
Solution
This problem can be solved using 2 heaps and the median can always be accessed in O(1) time.
Here's how you use both heaps. Note that I'm assuming you don't know the number of elements, and this is why we must pop until we pop something from the min heap that is larger than or equal to what we pop from the max heap. Note that we return the average because in the case of a set like {1, 2, 3, 4} the median is actually 2.5 (the average of the two "middle" values). I'm assuming double as the value type, but this can obviously be anything. Here:
double min = minheap.pop();
double max = maxheap.pop();
while(min < max) {
min = minheap.pop();
max = maxheap.pop();
}
return (min + max) / 2;
Since popping is O(log n) and we have to pop O(n / 2) values, this is O(n log n).
A working implementation in java, using 2 heaps, O(n log n). At any time I keep the two heaps balanced in size (ie. they differ at most by 1, if we entered n elements such that n%2==1). Getting the median is O(1). Adding a new element is O(log n).
public class MedianOfStream {
private int count;
private PriorityQueue<Integer> highs, lows;
public MedianOfStream() {
highs = new PriorityQueue<Integer>(11, new Comparator<Integer>() {
#Override
public int compare(Integer arg0, Integer arg1) {
return arg0.compareTo(arg1);
}
});
lows = new PriorityQueue<Integer>(11, new Comparator<Integer>() {
#Override
public int compare(Integer arg0, Integer arg1) {
return arg1.compareTo(arg0);
}
});
}
private int getMedian() {
if (count == 0)
return 0;
if (lows.size() == highs.size()) {
return (lows.peek() + highs.peek()) / 2;
} else if (lows.size() < highs.size()) {
return highs.peek();
}
return lows.peek();
}
private void swap(){
int h = highs.poll();
int l = lows.poll();
highs.add(l);
lows.add(h);
}
public int updateMedian(int n) {
count++;
if (count == 1)
lows.add(n);
else if (count==2) {
highs.add(n);
if(highs.peek()<lows.peek()) {
swap(); // O(log n)
}
}
else {
if (n > highs.peek()) {
lows.add(highs.poll()); // O(log n)
highs.add(n); // O(log n)
} else {
highs.add(lows.poll()); // O(log n)
lows.add(n); // O(log n)
}
if(highs.peek()<lows.peek()) {
swap(); // O(log n)
}
}
// if we added an even # of items,
// the heaps must be exactly the same size,
// otherwise we tolerate a 1-off difference
if (Math.abs(lows.size() - highs.size()) > (count % 2)) {
if (lows.size() < highs.size()) {
lows.add(highs.poll()); // O(log n)
} else {
highs.add(lows.poll()); // O(log n)
}
}
return getMedian(); // O(1)
}
}
Popping from a heap is an O(log N) operation, so you can achieve O(N log N) by popping half the elements from one of the heaps and taking the last popped value (you'd have to handle edge cases). This doesn't take advantage of the other heap though.
You can achieve O(N) using the selection algorithm, but the constant factor is very high. The former suggestion is probably better if you already have a heap.
JavaScript solution using two heaps:
function addNewNumber(minHeap, maxHeap, randomNumber) {
if (maxHeap.size() === minHeap.size()) {
if (minHeap.peek() && randomNumber > minHeap.peek()) {
maxHeap.insert(minHeap.remove());
minHeap.insert(randomNumber);
} else {
maxHeap.insert(randomNumber);
}
} else {
if (randomNumber < maxHeap.peek()) {
minHeap.insert(maxHeap.remove());
maxHeap.insert(randomNumber);
} else {
minHeap.insert(randomNumber);
}
}
}
function getMedian(minHeap, maxHeap) {
if (!maxHeap.size()) {
return 0;
}
if (minHeap.size() === maxHeap.size()) {
return (minHeap.peek() + maxHeap.peek()) / 2;
} else {
return maxHeap.peek();
}
}

Resources