Friday, May 25, 2018

LeetCode 716 - Max Stack

https://leetcode.com/articles/max-stack/
https://blog.csdn.net/magicbean2/article/details/79327801
http://www.cnblogs.com/grandyang/p/7823424.html
Design a max stack that supports push, pop, top, peekMax and popMax.
1. push(x) -- Push element x onto stack.
2. pop() -- Remove the element on top of the stack and return it.
3. top() -- Get the element on the top.
4. peekMax() -- Retrieve the maximum element in the stack.
5. popMax() -- Retrieve the maximum element in the stack, and remove it. If you find more than one maximum elements, only remove the top-most one.
Example 1:
MaxStack stack = new MaxStack();
stack.push(5);
stack.push(1);
stack.push(5);
stack.top(); -> 5
stack.popMax(); -> 5
stack.top(); -> 1
stack.peekMax(); -> 5
stack.pop(); -> 1
stack.top(); -> 5

Note:
1. -1e7 <= x <= 1e7
2. Number of operations won't exceed 10000.
3. The last four operations won't be called when stack is empty.

A regular stack already supports the first 3 operations, so we focus on the last two.
For peekMax, we remember the largest value we've seen on the side. For example if we add [2, 1, 5, 3, 9], we'll remember [2, 2, 5, 5, 9]. This works seamlessly with pop operations, and also it's easy to compute: it's just the maximum of the element we are adding and the previous maximum.
For popMax, we know what the current maximum (peekMax) is. We can pop until we find that maximum, then push the popped elements back on the stack.
Our implementation in Python will showcase extending the list class.

• Time Complexity: $O(N)$ for the popMax operation, and $O(1)$ for the other operations, where $N$ is the number of operations performed.
• Space Complexity: $O(N)$, the maximum size of the stack.
class MaxStack {
Stack<Integer> stack;
Stack<Integer> maxStack;

public MaxStack() {
stack = new Stack();
maxStack = new Stack();
}

public void push(int x) {
int max = maxStack.isEmpty() ? x : maxStack.peek();
maxStack.push(max > x ? max : x);
stack.push(x);
}

public int pop() {
maxStack.pop();
return stack.pop();
}

public int top() {
return stack.peek();
}

public int peekMax() {
return maxStack.peek();
}

public int popMax() {
int max = peekMax();
Stack<Integer> buffer = new Stack();
while (top() != max) buffer.push(pop());
pop();
while (!buffer.isEmpty()) push(buffer.pop());
return max;
}
}

Using structures like Array or Stack will never let us popMax quickly. We turn our attention to tree and linked-list structures that have a lower time complexity for removal, with the aim of making popMax faster than $O(N)$ time complexity.
Say we have a double linked list as our "stack". This reduces the problem to finding which node to remove, since we can remove nodes in $O(1)$ time.
We can use a TreeMap mapping values to a list of nodes to answer this question. TreeMap can find the largest value, insert values, and delete values, all in $O(\log N)$ time.
Let's store the stack as a double linked list dll, and store a map from value to a List of Node.
• When we MaxStack.push(x), we add a node to our dll, and add or update our entry map.get(x).add(node).
• When we MaxStack.pop(), we find the value val = dll.pop(), and remove the node from our map, deleting the entry if it was the last one.
• When we MaxStack.popMax(), we use the map to find the relevant node to unlink, and return it's value.
The above operations are more clear given that we have a working DoubleLinkedList class. The implementation provided uses head and tail sentinels to simplify the relevant DoubleLinkedListoperations.
Time Complexity: $O(\log N)$ for all operations except peek which is $O(1)$, where $N$ is the number of operations performed. Most operations involving TreeMap are $O(\log N)$.

class MaxStack {
TreeMap<Integer, List<Node>> map;

public MaxStack() {
map = new TreeMap();
}

public void push(int x) {
if(!map.containsKey(x))
map.put(x, new ArrayList<Node>());
}

public int pop() {
int val = dll.pop();
List<Node> L = map.get(val);
L.remove(L.size() - 1);
if (L.isEmpty()) map.remove(val);
return val;
}

public int top() {
return dll.peek();
}

public int peekMax() {
return map.lastKey();
}

public int popMax() {
int max = peekMax();
List<Node> L = map.get(max);
Node node = L.remove(L.size() - 1);
if (L.isEmpty()) map.remove(max);
return max;
}
}

tail = new Node(0);
}

Node x = new Node(val);
x.next = tail;
x.prev = tail.prev;
tail.prev = tail.prev.next = x;
return x;
}

public int pop() {
}

public int peek() {
return tail.prev.val;
}

node.prev.next = node.next;
node.next.prev = node.prev;
return node;
}
}

class Node {
int val;
Node prev, next;
public Node(int v) {val = v;}
}

http://www.cnblogs.com/grandyang/p/4091064.html
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
• push(x) -- Push element x onto stack.
• pop() -- Removes the element on top of the stack.
• top() -- Get the top element.
• getMin() -- Retrieve the minimum element in the stack.
public class MinStack {
private Stack<Integer> s1 = new Stack<>();
private Stack<Integer> s2 = new Stack<>();

/** initialize your data structure here. */
public MinStack() {}

public void push(int x) {
s1.push(x);
if (s2.isEmpty() || s2.peek() >= x) s2.push(x);
}

public void pop() {
// Cannot write like the following:
// if (s2.peek() == s1.peek()) s2.pop();
// s1.pop();
int x = s1.pop();
if (s2.peek() == x) s2.pop();
}

public int top() {
return s1.peek();
}

public int getMin() {
return s2.peek();
}
}

public class MinStack {
private int min_val = Integer.MAX_VALUE;
private Stack<Integer> s = new Stack<>();

/** initialize your data structure here. */
public MinStack() {}

public void push(int x) {
if (x <= min_val) {
s.push(min_val);
min_val = x;
}
s.push(x);
}

public void pop() {
if (s.pop() == min_val) min_val = s.pop();
}

public int top() {
return s.peek();
}

public int getMin() {
return min_val;
}
}