记录技巧。
有三种解法,比较想记的是后两种,尤其是第二种。
第一种:
暴力求解
枚举每个‘(’,用栈或者给’(’’)'赋值成-1和1的方式遍历过来,找到那个最长的即可。
时间复杂度为n^2,空间复杂度为n,也可以是1。这里很简单,不细写了。
第二种:
给每个元素标上对应的下标值。
纯思路是用栈来配对’(‘和’)’,并利用他们的下标之差计算匹配成功的长度。
然后找到最长的。
然后我就开始模拟,然后出现了各种情况,一言难尽,当然我觉得直接模拟肯定是可行的,但我还是选择了找找高明的做法。于是就看到了大佬的方法。
开一个栈,先给他入上第一个值-1。这个压入-1的手法太高明了。
遇到’(‘就入栈
遇到‘)’就弹出栈顶,栈顶弹出之后,然后此时遇到的‘)’的下标与新栈顶的值做差,这时的查就是这轮的长度。但如果发现新栈顶的值是-1,那需要弹出-1,再把此时’)'的下标压入栈内。
那为什么要这么操作呢?
看看代码,再画几个样例就自然明白了。
class Solution {
public:
int longestValidParentheses(string s) {
int len = s.size(), mi=0;
stack<int> st;;
st.push(-1);
for(int i=0; i<len; i++){
if(s[i]=='('){
st.push(i);
}
else{
st.pop();
if(st.empty()){
st.push(i);
}
else{
mi = max(mi, i-st.top());
}
}
}
return mi;
}
};
很喜欢这种做法,唯一不足的就是他的空间复杂度是n,时间复杂度也是n。
时间复杂度倒是无法再优化了,空间复杂度还可以再优化。
第三种:
从左到右或从右往左遍历
遍历的时候记录下‘(’和’)'各自出现的次数。
比如正向遍历时,
当两者出现次数相等时说明两着匹配,此时记录一下,当右括号多余左括号时,说明这个多出来的右括号不可能会在后面被匹配,此时将两者次数都置零。重复这个操作,此间记录最大值。
然后我就直接很快的撸出了代码,但是发现有情况没有考虑到,
比如:()(()()
这种中间被一个多出来的’('给断开的无法找出正确答案。
怎么办呢
再逆向遍历一次。
class Solution {
public:
int longestValidParentheses(string s) {
int len = s.size(), mi=0, mm = 0, l=0, r=0;
for(int i=len-1; i>=0; --i){
if(s[i]=='(') l ++;
else r ++;
if(l>r) l=0, r=0;
if(l==r) mi=max(mi, r*2);
}
l = 0, r=0;
for(int i=0; i<len; ++i){
if(s[i]=='(') l ++;
else r ++;
if(l<r) l=0, r=0;
if(l==r) mm=max(mm, r*2);
}
return max(mm, mi);
}
};
时间复杂度为n,空间复杂度为1。