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.


 

思路:要找到最长的匹配括号子串,需要保存已经匹配成功的子串“状态”,状态指的是已匹配好的子串的位置,比如例子:”()(((()((()”,当匹配到橘黄色的括号时,前面的红色绿色的括号的状态也需要保留,如果橘黄色的括号后边在多加几个’)’的话,比如变成” ()(((()((()   )))))”后,所有的括号都变成匹配的了。所以,该问题的关键就是:如何保存已经匹配好的子串的状态!!


一般在匹配括号的时候,都会使用到栈这种数据结构,当遇到”(”的时候,就入栈,遇到”)”的时候,就将栈顶弹出,表示一个匹配的括号。


因此,该题也可以利用栈这种结构,然后,开辟一个跟原字符串同样长度的空间ressets,ressets中只记录那些匹配好的子串,而无法匹配的括号则不记录。扫描源字符串,当遇到”(”的时候,将该”(”的位置入栈,当弹出栈的时候,就可以知道匹配的括号的具体位置,这样,就可以在ressets中记录匹配好的子串了。扫描完原始字符串之后,ressets中就记录了所有已经匹配好的子串,再次扫描ressets,就可以得到最长匹配子串的长度了。代码如下:

 

typedef struct
{
    int *sets;
    int len;
    int top;
}Stack;

int push(Stack *s, int key)
{
    if(s->top >= s->len)  return -1;
    s->sets[s->top ++] = key;
    return 0;
}

int pop(Stack *s)
{
    if(s->top == 0)   return -1;
    return s->sets[-- s->top];
}

Stack *initstack(int stlen)
{
    Stack *st = calloc(1, sizeof(Stack));
    st->sets = calloc(stlen, sizeof(int));
    st->len = stlen;
    st->top = 0;
    return st;
}

int longestValidParentheses(char* s) 
{
    int slen = strlen(s);
    char *ressets = calloc(slen+1 ,sizeof(char));

    Stack *st = initstack(slen);

    int reslen = 0;
    int i, j;
    for(i = 0; i < slen; i++)
    {
        switch(s[i])
        {
            case '(':
                push(st, i);
                break;
            case ')':
                if(st->top == 0)    continue;
                j = pop(st);
                ressets[j] = '(';
                ressets[i] = ')';
                break;
        }
    }

    i = 0; 
    while(i < slen)
    {
        if(ressets[i] == '\0')
        {
            i++;
            continue;
        }   

        int tmplen = strlen(ressets+i);
        if(reslen < tmplen)
        {
            reslen = tmplen;
        }
        i += tmplen;
    }
    return reslen;
}

 


这种算法,时间和空间复杂度都是O(n),但是,其实ressets并不是必须的,考虑下面例子:”)))(()())”,该字符串,前三个字符都是无法匹配的字符,因此,从第四个字符开始,才是可能的最长子串的起点。扫描该字符串:将”(”和” (”入栈,扫描到” )”时,弹出栈顶元素,此时匹配的子串长度为当前栈顶”(”和” )”之间的距离(减1),然后,接着将”(”入栈,扫描到”)”时,弹出栈顶元素,此时匹配的子串长度为当前栈顶”(”和” )”之间的距离(减1),扫描到”)”时,弹出栈顶,栈变空,子串的长度,是起点到”)”之间的距离,所以,代码如下:

int longestValidParentheses2(char* s) 
{
    int slen = strlen(s);

    Stack *st = initstack(slen);

    int reslen = 0;
    int tmplen = 0;
    int startindex = -1;
    int i;
    for(i = 0; i < slen; i++)
    {
        switch(s[i])
        {
            case '(':
                push(st, i);
                break;
            case ')':
                if(st->top == 0)
                {
                    startindex = i;
                }
                else
                {
                    pop(st);
                    if(st->top == 0)
                    {
                        tmplen = i-startindex;
                    }
                    else
                    {
                        tmplen = i - st->sets[st->top-1];
                    }
                    if(reslen < tmplen) reslen = tmplen;
                }
                break;
        }
    }
    return reslen;
}



参考:

https://github.com/haoel/leetcode/blob/master/algorithms/longestValidParentheses/longestValidParentheses.cpp

 





 

posted @ 2015-07-10 10:54  gqtc  阅读(134)  评论(0编辑  收藏  举报