显示标签为“stack”的博文。显示所有博文
显示标签为“stack”的博文。显示所有博文

2015年6月24日星期三

Maximal Rectangle leetcode

Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and return its area.
解法转自:http://codeganker.blogspot.com/2014/04/maximal-rectangle-leetcode.html
"这道题的解法灵感来自于Largest Rectangle in Histogram这道题,假设我们把矩阵沿着某一行切下来,然后把切的行作为底面,将自底面往上的矩阵看成一个直方图(histogram)。直方图的中每个项的高度就是从底面行开始往上1的数量。根据Largest Rectangle in Histogram我们就可以求出当前行作为矩阵下边缘的一个最大矩阵。接下来如果对每一行都做一次Largest Rectangle in Histogram,从其中选出最大的矩阵,那么它就是整个矩阵中面积最大的子矩阵。
算法的基本思路已经出来了,剩下的就是一些节省时间空间的问题了。
我们如何计算某一行为底面时直方图的高度呢? 如果重新计算,那么每次需要的计算数量就是当前行数乘以列数。然而在这里我们会发现一些动态规划的踪迹,如果我们知道上一行直方图的高度,我们只需要看新加进来的行(底面)上对应的列元素是不是0,如果是,则高度是0,否则则是上一行直方图的高度加1。利用历史信息,我们就可以在线行时间内完成对高度的更新。我们知道,Largest Rectangle in Histogram的算法复杂度是O(n)。所以完成对一行为底边的矩阵求解复杂度是O(n+n)=O(n)。接下来对每一行都做一次,那么算法总时间复杂度是O(m*n)。
空间上,我们只需要保存上一行直方图的高度O(n),加上Largest Rectangle in Histogram中所使用的空间O(n),所以总空间复杂度还是O(n)。代码"

public class Solution {
    public int maximalRectangle(char[][] matrix) {
        if (matrix.length == 0 || matrix[0].length == 0 || matrix == null) {
            return 0;
        }
        int m = matrix.length;//列数
        int n = matrix[0].length;//行数
        int[] height = new int[n];//对每一列构造数组
        int max = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == '0') {
                    height[j] = 0;
                } else {
                    height[j] += 1;
                }
            }
            max = Math.max(helper(height), max);//从上至下每层
        }
        return max;
    }
    public int helper(int[] height) {
        Stack<Integer> stack = new Stack<Integer>();
        int max = 0;
        for (int i = 0; i <= height.length; i++) {
            int h;
            if (i == height.length) {// fake一个最终高度为1的直放
                h = 0;
            } else {
                h = height[i];//当前高度
            }
            while (!stack.isEmpty()) {
                if (h < height[stack.peek()]) {
                    int indx = stack.pop();
                    int k = i;//计算直方的底用于求面积
                    if (!stack.isEmpty()) {
                        k = i - stack.peek() - 1;
                    }
                    max = Math.max(max, k*height[indx]);
                } else {
                    break;
                }
            }
            stack.push(i);
        }
        return max;
    }
}

Longest Valid Parentheses leetcode

Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring.
For "(()", the longest valid parentheses substring is "()", which has length = 2.
Another example is ")()())", where the longest valid parentheses substring is "()()", which has length = 4.
这道题要求的事最长有效的括号长度 而不是有效括号个数
用stack来完成, 但是stack内装括号所在的index 而不是括号本身, 遇到左括号就入栈 
遇到右括号就出栈并且判断当前序列是否最长. 
1.如果当前的栈是空的 那么久没有元素出栈 记录start的位置为 i + 1(右括号的下一位为有效起始位置)
2. 如果栈不空, 就弹出一个左括号, 2.1:弹出之后如果栈空了 则说明当前所有括号匹配 长度就是 i - start + 1;  2.2 如果当前栈不空, 则当前最大长度就是 i - (栈顶元素 + 1) + 1 = i - stack.peek()

时间复杂度O(n)


public class Solution {
    public int longestValidParentheses(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        Stack<Integer> stack = new Stack<Integer>();
        int start = 0;
        int max = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                stack.push(i);
            } else {
                if (stack.isEmpty()) {
                    start = i + 1;//下一个位置为有效的起始位置
                } else {
                    stack.pop();
                    if (stack.isEmpty()) {
                        max = Math.max(max, i - start + 1);//因为要求长度 所以i - start 后面还要+1
                    } else {
                        max = Math.max(max, i - stack.peek()); // stack.peek()的下一位到i的距离是最大长度 因为栈内都是左括号 栈顶的下一位不可能是右括号
                    }
                }
            }
        }
        return max;
    }
}

Evaluate Reverse Polish Notation leetcode

Evaluate the value of an arithmetic expression in Reverse Polish Notation.
Valid operators are +-*/. Each operand may be an integer or another expression.
Some examples:
  ["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9
  ["4", "13", "5", "/", "+"] -> (4 + (13 / 5)) -> 6

wiki中的例子

中缀表达式“5 + ((1 + 2) * 4) − 3”写作
5 1 2 + 4 * + 3 −
下表给出了该逆波兰表达式从左至右求值的过程,堆栈栏给出了中间值,用于跟踪算法。
输入操作堆栈注释
5入栈5
1入栈5, 1
2入栈5, 1, 2
+加法运算5, 3(1, 2)出栈;将结果(3)入栈
4入栈5, 3, 4
*乘法运算5, 12(3, 4)出栈;将结果(12)入栈
+加法运算17(5, 12)出栈;将结果 (17)入栈
3入栈17, 3
减法运算14(17, 3)出栈;将结果(14)入栈
计算完成时,栈内只有一个操作数,这就是表达式的结果:14
上述运算可以重写为如下运算链方法(用于HP的逆波兰计算器):[3]
1 2 + 4 * 5 + 3 −

维护一个栈,把字符都转换成数字入栈, 遇到符号就对栈内数字做运算得出结果再入栈
String 不用== 用.equals()

public class Solution {
    public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<Integer>();
        for (String s : tokens) {
            if (s.equals("+")) {
                stack.push(stack.pop() + stack.pop());
            } else if (s.equals("-")) {
                stack.push(-stack.pop() + stack.pop());
            } else if (s.equals("*")) {
                stack.push(stack.pop() * stack.pop());
            } else if (s.equals("/")) {
                int a = stack.pop();
                int b = stack.pop();
                stack.push(b / a);
            } else {
                stack.push(Integer.parseInt(s));
            }
        }
        return stack.pop();
    }
}

2015年5月31日星期日

Valid Parentheses leetcode

Given a string containing just the characters '('')''{''}''[' and ']', determine if the input string is valid.
The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and "([)]" are not.
用stack实现, 左括号都push到stack中 注意返回时候是要确保stack为空才能true

时间O(n)
 
public class Solution {
    public boolean isValid(String s) {
        if (s == null || s.length() == 0) {
            return false;
        }
        Stack<Character> stack = new Stack<Character>();
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(' ||s.charAt(i) == '[' || s.charAt(i) == '{') {
                stack.push(s.charAt(i));
            } else if (s.charAt(i) == ')' || s.charAt(i) == ']' || s.charAt(i) == '}') {
                if (stack.size() == 0) {
                    return false;
                }
                char c = stack.pop();
                if (s.charAt(i) == ')') {
                    if (c != '(') {
                        return false;
                    }
                } else if (s.charAt(i) == ']') {
                    if (c != '[') {
                        return false;
                    }
                } else {
                    if (c != '{') {
                        return false;
                    }
                }
            }
        }
        return stack.size() == 0; //防止有stack没清空
    }
}
//
public class Solution {
    public boolean isValid(String s) {
        HashMap<Character, Character> map = new HashMap<Character, Character>();
        map.put('(', ')');
        map.put('{', '}');
        map.put('[', ']');
        Stack<Character> stack = new Stack<Character>();
        for (int i = 0; i < s.length(); i++) {
            if (map.containsKey(s.charAt(i))) {
                stack.push(s.charAt(i));
            } else {
                if (stack.isEmpty() || map.get(stack.pop()) != s.charAt(i)) {
                    return false;
                }
            }
        }
        return stack.isEmpty();
    }
}

2015年5月20日星期三

Largest Rectangle in Histogram leetcode

Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.
Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].
The largest rectangle is shown in the shaded area, which has area = 10 unit.
For example,
Given height = [2,1,5,6,2,3],
return 10.

维护一个栈, 这个栈从低向上的高度是依次递增的,如果遇到当前bar高度比栈顶元素低,那么就出栈直到满足条件,过程中检测前面满足条件的矩阵。

1.当栈空或者当前高度大于栈顶下标所指示的高度时,当前下标入栈。否则,2:当前栈顶出栈,并且用这个下标所指示的高度计算面积。然后大于当前高度的栈顶依次出栈并计算高度.如果栈已经为空,说明到目前为止所有元素(当前下标元素除外)都比出栈元素高度要大(否则栈中肯定还有元素),所以矩阵面积就是高度乘以当前下标i。如果栈不为空,那么就是从当前栈顶元素的下一个到当前下标的元素之前都比出栈元素高度大(因为栈顶元素第一个比当前出栈元素小的)
3. fake一个最后一个直方高度为0 (这样面积也为0)
4. 因为每次入栈计算的面积都是出栈元素的面积 所以最后添加一个高度为0的元素让所有的元素都出栈计算面积

首先,如果栈是空的,那么索引i入栈。那么第一个i=0就进去吧。注意栈内保存的是索引,不是高度。然后i++。
然后继续,当i=1的时候,发现h[i]小于了栈内的元素,于是出栈。(由此可以想到,哦,看来stack里面只存放单调递增的索引
这时候stack为空,所以面积的计算是h[t] * i.t是刚刚弹出的stack顶元素。也就是蓝色部分的面积。
继续。这时候stack为空了,继续入栈。注意到只要是连续递增的序列,我们都要keep pushing,直到我们遇到了i=4,h[i]=2小于了栈顶的元素。
这时候开始计算矩形面积。首先弹出栈顶元素,t=3。即下图绿色部分。
接下来注意到栈顶的(索引指向的)元素还是大于当前i指向的元素,于是出栈,并继续计算面积,桃红色部分。
最后,栈顶的(索引指向的)元素大于了当前i指向的元素,循环继续,入栈并推动i前进。直到我们再次遇到下降的元素,也就是我们最后人为添加的dummy元素0.
同理,我们计算栈内的面积。由于当前i是最小元素,所以所有的栈内元素都要被弹出并参与面积计算。
注意我们在计算面积的时候已经更新过了maxArea。
总结下,我们可以看到,stack中总是保持递增的元素的索引,然后当遇到较小的元素后,依次出栈并计算栈中bar能围成的面积,直到栈中元素小于当前元素。
public class Solution {
    public int largestRectangleArea(int[] height) {
        Stack<Integer> stack = new Stack<Integer>();
        int[] tem = Arrays.copyOf(height, height.length + 1);
        int max = 0;
        int i = 0;
        while (i < tem.length) {
            if (stack.isEmpty() || tem[i] >= tem[stack.peek()]) {
                stack.push(i);
                i++;
            } else {
                int t = stack.pop();
                if (!stack.isEmpty()) {
                    max = Math.max(max, tem[t] * (i - stack.peek() - 1));
                } else {
                    max = Math.max(max, tem[t] * i);
                }
            }
        }
        return max;
    }
}
public class Solution {
    public int largestRectangleArea(int[] height) {
        Stack<Integer> stack = new Stack<Integer>();
        int max = 0;
        for (int i = 0; i <= height.length; i++) {
            int h;
            if (i == height.length) {
                h = 0;
            } else {
                h = height[i];
            }
            if (stack.isEmpty() || h >= height[stack.peek()]) {
                stack.push(i);
            } else {
                while (!stack.isEmpty() && h < height[stack.peek()]) {
                    int k = stack.pop();
                    if (stack.isEmpty()) {
                        max = Math.max(i * height[k], max);
                    } else {
                        max = Math.max(max, (i - stack.peek() - 1)*height[k]);
                    }
                }
                stack.push(i);
            }
        }
        return max;
    }
}

2015年5月19日星期二

Implement Queue by Two Stacks

As the title described, you should only use two stacks to implement a queue's actions.
The queue should support push(element)pop() and top() where pop is pop the first(a.k.a front) element in the queue.
Both pop and top methods should return the value of first element.
Example
For push(1), pop(), push(2), push(3), top(), pop(), you should return 12 and 2
Challenge
implement it by two stacks, do not use any other data structure and push, pop and top should be O(1) by AVERAGE
用两个stack来实现queue 第一个stack正向装入数字 然后pop出来 push到第二个stack中
每次判定stack2是否为empty(这样做可以防止后来加入的数字push到stack2中 这样顺序就乱了 所以要等stack2 是空的时候才再次网stack2里面push数字) 如果为empty继续push入stack1 pop出来的数 

public class Solution {
    private Stack<Integer> stack1;
    private Stack<Integer> stack2;

    public Solution() {
       stack1 = new Stack<Integer>();
       stack2 = new Stack<Integer>();
    }
    public void push(int element) {
        stack1.push(element);
    }

    public int pop() {
        if (stack2.empty()) {
            while (!stack1.empty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }

    public int top() {
        if (stack2.empty()) {
            while (!stack1.empty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.peek();
    }
}

Min Stack leetcode

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.
在维护stack同时维护一个minstack, 记录stack内最小值 当stack push新值的时候 minstack 将新值与它最上面的值比较 哪个小就新push哪个 这样ministack最顶层都是当前stack的最小值

class MinStack {
    private Stack<Integer> stack = new Stack<Integer>();
    private Stack<Integer> ministack = new Stack<Integer>();
    public void push(int x) {
       stack.push(x);
        if (ministack.empty()) {
            ministack.push(x);
        } else if (ministack.peek() < x) {
            ministack.push(ministack.peek());
        } else {
            ministack.push(x);
        } 
    }

    public void pop() {
        ministack.pop();
        stack.pop();
    }

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

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