LeetCode 之堆栈 stack

来源:互联网 发布:拍摄淘宝图要如何布光 编辑:程序博客网 时间:2024/05/19 06:48

1. Valid Parenthese

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.

栈匹配,遇到左符号进栈,遇到右符号对比出栈

如果最后栈的值不为0,则不为Parenthese

bool isValid(string s) {        if(s.size()%2 == 1 || s.size() == 0)        return false;    vector<char> sta;    sta.push_back(s[0]);    for(int i=1; i< s.size(); i++){        if(s[i] == '(' || s[i]=='[' || s[i]=='{'){            sta.push_back(s[i]);            continue;           }        char current = sta.back();        if(s[i] == ')' && current != '(' )            return false;        if(s[i] == ']' && current != '[')            return false;        if(s[i] == '}' && current != '{')            return false;        sta.pop_back();    }    if(sta.size() != 0 ) return false;    return true;    }

2. Longest Valid Parentheses

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.

维护一个堆栈,只存储没有match的左边际

int longestValidParentheses(string s) {    int result = 0;    int lastleft = 0;    if(s.size()<2) return result;    stack<int> sta;    for(int i=0; i<s.size(); i++){        if(s[i]=='('){            sta.push(i);           }        else{            if(!sta.empty()){                sta.pop();                if(!sta.empty())                    result = max(result, i-sta.top());                else                    result = max(result,i-lastleft+1);            }else{                lastleft = i+1;            }        }    }    return result;}

3. Largest Rectangle in Histogram 

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.

int largestRectangleArea(vector<int> &height) {    int maxArea = 0;    height.push_back(0);    stack<int> stk;    int i=0;    while(i<height.size()){        if(stk.empty() || height[stk.top()] <= height[i])            stk.push(i++);        else{            int t = stk.top();            stk.pop();            maxArea = max(maxArea, height[t]*(stk.empty()? i:i-stk.top()-1));        }    }    return maxArea;}

参考来自:http://blog.csdn.net/doc_sgl/article/details/11805519


就用题目中的[2,1,5,6,2,3]来解释一下这段代码吧。

首先,如果栈是空的,那么索引i入栈。那么第一个i=0就进去吧。注意栈内保存的是索引,不是高度。然后i++。

然后继续,当i=1的时候,发现h[i]小于了栈内的元素,于是出栈。(由此可以想到,哦,看来stack里面只存放height单调递增的索引

这时候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能围成的面积,直到栈中元素小于当前元素。

可以这样理解这个算法,看下图。

例如我们遇到最后遇到一个递减的bar(红色)。高度位于红线上方的(也就是算法中栈里面大于最右bar的)元素,他们是不可能和最右边的较小高度bar围成一个比大于在弹栈过程中的矩形面积了(黄色面积),因为红色的bar对他们来说是一个短板,和红色bar能围成的最大面积也就是红色的高度乘以这些“上流社会”所跨越的索引范围。但是“上流社会”的高度个个都比红色bar大,他们完全只计算彼此之间围成的面积就远远大于和红色bar围成的任意面积了。所以红色bar是不可能参与“上流社会”的bar的围城的。因为虽然长度不占优势,但是团结的力量是无穷的。它还可以参与“比较远的”比它还要屌丝的bar的围城。他们的面积是有可能超过上流社会的面积的,因为距离啊!所以弹栈到比红色bar小就停止了。

另外一个细节需要注意的是,弹栈过程中面积的计算。

h[t] * (stack.empty() ? i : i - stack.top() - 1)

h[t]是刚刚弹出的栈顶端元素。此时的面积计算是h[t]和前面的“上流社会”能围成的最大面积。这时候要注意哦,栈内索引指向的元素都是比h[t]小的,如果h[t]是目前最小的,那么栈内就是空哦。而在目前栈顶元素和h[t]之间(不包括h[t]和栈顶元素),都是大于他们两者的。如下图所示:

那h[t]无疑就是Stack.top()和t之间那些上流社会的短板啦,而它们的跨越就是i - Stack.top() - 1。

所以说,这个弹栈的过程也是维持程序不变量的方法啊:栈内元素一定是要比当前i指向的元素小的。


4. Maximal Rectangle

Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and return its area

例如矩阵是下图这样的,结果应该是图中红色区域的面积:

一般人拿到这个题目,除非做过类似的,很难一眼找出一个方法来,更别说找一个比较优化的方法了。

首先一个难点就是,你怎么判断某个区域就是一个矩形呢?

其次,以何种方式来遍历这个2D的matrix呢?

一般来说,对这种“棋盘式”的题目,像什么Queen啦,象棋啦,数独啦,如果没有比较明显的遍历方式,可以采用一行一行地遍历。

然后,当遍历到(i, j)的时候,该做什么样的事情呢?想想,嗯,那我可不可以简单看看,以(i,j)为矩形左上角,能不能形成一个矩形,能不能形成多个矩形?那形成的矩形中,我们能不能找一个最大的呢?

首先,如果(i, j)是0,那肯定没法是矩形了。

如果是1,那么我们怎么找以它为左上角的矩形呢?呼唤画面感!

图中圈圈表示左上角的1,那么矩形的可能性是。。。太多啦,怎么数呢?

我们可以试探地从左上角的1所在的列开始,往下数数,然后呢,比如在第一行,例如是蓝色的那个矩形,我们看看在列上,它延伸了多远,这个面积是可以算出来的。然后继续,第二行,例如是那个红色的矩形,再看它延伸到多远,哦,我们知道,比第一行近一些,我们也可以用当前离第一行的行数,乘以延伸的距离,得到当前行表示的矩形面积。但是到了第一个虚线的地方,它远远超过了上面的其他所有行延伸的距离了,注意它的上方都是空心的哦,所以,我们遇到这种情况,计算当前行和左上角1围成的面积的时候,只能取所有前面最小的延伸距离乘以当前离第一行的行数。其实,这对所有情况都是这样的,是吧?于是,我们不是就有方法遍历这些所有的矩形了嘛。

但是,当我们在数这个矩形的时候越来越像leetcode_question_85 Largest Rectangle in Histogram这道题了,不是吗?我们讨论了柱状图的最大矩形面积,那可以O(n)的,学以致用呀!btw,leetcode的这两题也是挨一块儿的,用心良苦。。。。

上面的矩阵就成这样了:


每一行都是一次柱状图的最大矩形面积了。dp[i][j]就是当前的第j列到第i行连续1的个数。


leetcode的讨论组还给出了一个比较难理解的方法。。


int largestRectangleArea(int *height, int length) {    int maxArea = 0;    stack<int> stk;    int i=0;    while(i<length){        if(stk.empty() || height[stk.top()] <= height[i])            stk.push(i++);        else{            int t = stk.top();            stk.pop();            maxArea = max(maxArea, height[t]*(stk.empty()? i:i-stk.top()-1));        }    }    return maxArea;}// use stack similar with largestRectangleAreaint maximalRectangle(vector<vector<char> > &matrix) {    int m = matrix.size();    if(m == 0) return 0;    int n = matrix[0].size();    if(n==0) return 0;    int **dp = new int *[m];    for(int i=0;i<m;i++){        dp[i] = new int[n+1];        memset(dp[i],0,sizeof(int)*(n+1));// allocate and value array in memory    }    for(int j=0;j<n;j++)        if(matrix[0][j]=='1') dp[0][j] =1;    for(int j=0;j<n;j++)//from matrix top to bottom        for(int i=1;i<m;i++)            if(matrix[i][j]=='1') dp[i][j] = dp[i-1][j]+1;    int maxArea =0;    for(int i=0;i<m;i++){        int tmp = largestRectangleArea(dp[i],n+1);        if(tmp>maxArea)            maxArea = tmp;    }        return maxArea;}


5. 

Evaluate Reverse Polish Notation

 

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
Analysis:

This is a classical algorithm question. The polish notation is the similar to the postorder traversal of the binary tree, and can be efficiently solved using the data structure-----stack.

The concept is:
When meeting the number, push into the stack.
When meeting the operator, pop the top 2 number and compute the value, then push the result back into the stack.
Until the end of the expression.
Output the top (last) value in the stack.

Details can be seen in the code below, there is some points need to be careful with, e.g. the order the the two numbers for the operator.
int evalRPN(vector<string> &tokens) {    string op = "+-*/";// to check the operator    stack<int> st;    if(tokens.size()<=0) return 0;    for(int i=0;i<tokens.size();i++){        string tok = tokens[i];        int o = op.find(tok);// operator number        if(o!=-1){// is an operator            if(st.size()<2) return -1;            else{                int v1 = st.top();                st.pop();                int v2 = st.top();                st.pop();                if(o==0){st.push(v2+v1);}                if(o==1){st.push(v2-v1);}                if(o==2){st.push(v2*v1);}                if(o==3){st.push(v2/v1);}            }        }else{// is a number            st.push(atoi(tok.c_str()));        }    }    return st.top();}



未完待续

0 0
原创粉丝点击