思路: 是否合法,最简单判断方法是用栈。只有一种括号,栈中存放元素只需要左括号的下标。 每一次遇到),就把栈顶的一个左括号下标和当前下标一起压入vector中,将这个vector排序,就是所有合法子串的下标。遍历这个vector,找连续的最长值就可以。排序复杂度O(nlogn),除此之外遍历一次字符串,一次vector,O(n)。
int longestValidParentheses(string s) { stack<int> st; vector<int> index; int longest=0; for(int i=0;i<s.size();i++){ if(s[i]=='(') st.push(i); else{ if(st.size()){ int tem=st.top(); st.pop(); index.push_back(tem); index.push_back(i); } } } if(index.size()==0) return 0; sort(index.begin(),index.end()); int now=0; for(int i=0;i<index.size()-1;i++){ //cout<<index[i]<<' '; //cout<<index[i+1]<<' '; now++; //cout<<now<<endl; if(index[i+1]!=index[i]+1){ longest=max(longest,now); now=0; } } now++; longest=max(longest,now); return longest; }
改良的stack解法:在想出上面解法的过程中,没用当前i 减去栈顶元素下标的原因是,遇到连续一串的()()(),没办法连起来;实际上这里只要加入一个小trick就好了:每一次遇到)的时候,先pop,再算i - stack.top(), 因为stack.top()这个时候,是前面最近一个还没被消掉的 (, 减去它就是当前最长串的长度。而当栈空的时候,就说明至此为止,前面所有的(都被消掉了(或者根本没有左括号),所以这个)是不配对的,把它的下标压进栈中,作为新的子串的起点前。
栈的最初要压入一个-1,相当于在最前面加一个dummy节点。
int longestValidParentheses(string s) { int longest=0; stack<int> st; st.push(-1); for(int i=0;i<s.size();i++){ if(s[i]=='(') st.push(i); else{ st.pop(); if(st.empty()){ st.push(i); } else{ longest=max(longest, i-st.top()); } } } return longest; }
解法2: dp,count[i]表示 结束于i的有效子串长度。count[i] 的计算:
- s[i]=='(" , 一定0
- s[i]==')',
-s[i-1]=='(', count[i]=count[i-2]+2;
-s[i-1]==')',就是有可能嵌套,要看s[i-count[i-1]-1]是否为‘(“,若是,为合法的嵌套,要跟这个嵌套子串前面可能的最长串合并。count[i]=count[i-1]+count[i-count[i-1]-2]+2.
-不是合法嵌套,在这个)处,应清零,count[i]=0;
int longestValidParentheses(string s) { if(!s.size()) return 0; int count[s.size()]; int longest=0; for(int i=0;i<s.size();i++){ if(s[i]=='(') count[i]=0; else{ if(i==0) count[i]=0; else if(s[i-1]=='('){ if(i-2>=0){ count[i]=count[i-2]+2; } else count[i]=2; } else{ if(i-count[i-1]-1>=0&&s[i-count[i-1]-1]=='('){ if(i-count[i-1]-2>=0){ count[i]=count[i-1]+count[i-count[i-1]-2]+2; } else count[i]=count[i-1]+2; } else{ count[i]=0; } } longest=max(longest,count[i]); } } return longest; }