与括号相关的几个小问题

最近在刷leetcode上的算法题,遇到几个与括号相关的题目。

第一题是关于括号配对是否有效。括号种类包括小括号,中括号,花括号。题目具体描述如下图:

解题思路:题目难度不大,将他理解为配对就行。使用栈是最方便的解法。我的第一反应不是栈,是最小单元剔除。因为括号需要成对出现,不管是嵌套还是并列括号,最小的单元都是一个成对的括号,剔除最里面的成对括号后,外层括号就又成为了最小的单元括号。按照这个思路,如果一个字符串能被剔除完则说明该字符串是一个有效的括号对。

 def isValid( s):
     dic = {'(':1,')':1,'{':2,'}':2,'[':3,']':3};
     list_s = list(s);
     while(len(list_s)>0 and len(list_s)%2==0):
         i = 0;
         n = len(list_s);
         while(i < n-1):
             if(list_s[i] != list_s[i + 1]):
                 if(dic[list_s[i]] == dic[list_s[i+1]]):
                     print(i,n);
                     list_s.pop(i);
                     list_s.pop(i);
                     break;
                 else:
                     i = i + 1;
             else:
                 i = i + 1;
         if(i == n-1):
             break;
     if(len(list_s)==0):
         return True;
     else:
         return False;

leetcode 上给出的解决方案是用栈的思想,易于理解,在这里一并给出。https://leetcode.com/problems/valid-parentheses/solution/

class Solution(object):
    def isValid(self, s):
        """
        :type s: str
        :rtype: bool
        """

        # The stack to keep track of opening brackets.
        stack = []

        # Hash map for keeping track of mappings. This keeps the code very clean.
        # Also makes adding more types of parenthesis easier
        mapping = {")": "(", "}": "{", "]": "["}

        # For every bracket in the expression.
        for char in s:

            # If the character is an closing bracket
            if char in mapping:

                # Pop the topmost element from the stack, if it is non empty
                # Otherwise assign a dummy value of '#' to the top_element variable
                top_element = stack.pop() if stack else '#'

                # The mapping for the opening bracket in our hash and the top
                # element of the stack don't match, return False
                if mapping[char] != top_element:
                    return False
            else:
                # We have an opening bracket, simply push it onto the stack.
                stack.append(char)

        # In the end, if the stack is empty, then we have a valid expression.
        # The stack won't be empty for cases like ((()
        return not stack

第二题是关于括号生成的问题。给出一个数字n 表示括号的对数,问一共有多少种括号组合情况,并打印出来。下图给出题目描述:

解决方案:这题的难度明显比第一题大,但是原理都是相通的。抓住其中相同点,就是不管括号怎么组合,其左右都是配对的。而且距离最近的左右括号组成一对,也就是说,从内往外生成括号看,生成一个左括号,下一个一定是右括号。按照这个思路,可以用递归实现。因为每一步都是相同的重复。

def generateParenthesis(N):
        res = []
        def inner(S = '', left = 0, right = 0):
            if len(S) == 2 * N:
                res.append(S);
                return ;
            if left < N:
                inner(S+'(', left+1, right);
            if right < left:
                inner(S+')', left, right+1);

        inner();
        return res;

leetcode上给出了三种解决方案。第一种是暴力搜索所有可能的情况,然后判断是否是有效的括号配对;第二种与上述一样,回溯递归生成括号;第三种就很巧妙,利用左右括号位置间的关系生成括号。左括号总在偶数位,右括号总在奇数位(下标从0开始)。下面给出leetcode 上的第一种和第三种方法的代码。https://leetcode.com/problems/generate-parentheses/solution/

#暴力搜索
def generateParenthesis( n):
        def generate(A = []):
            if len(A) == 2*n:
                if valid(A):
                    ans.append("".join(A))
            else:
                A.append('(')
                generate(A)
                A.pop()
                A.append(')')
                generate(A)
                A.pop()

        def valid(A):
            bal = 0
            for c in A:
                if c == '(': bal += 1
                else: bal -= 1
                if bal < 0: return False
            return bal == 0

        ans = []
        generate()
        return ans


#利用左右括号位置关系
def generateParenthesis( N):
        if N == 0: return ['']
        ans = []
        for c in xrange(N):
            for left in self.generateParenthesis(c):
                for right in self.generateParenthesis(N-1-c):
                    #从第一对括号开始往外、往内扩展
                    ans.append('({}){}'.format(left, right))
        return ans

第三题是最难的,我没有做出来。这题是说要在字符串中找出有效括号配对最长的字串的长度。我的算法解决没有括号嵌套的情况。当我看了leetcode 上的解决方案时恍然大悟,离成功仅有一步之遥。当时想到用栈,但没有想到将元素下标相减即为有效字符串长度。另外有个巧妙的设置也是我没有想到的。下图给出题目描述:

解决方案:此题在leetcode 上标记位Hard. 实力还不到家,需要在锻炼。最直接的方法还是栈,不过在使用栈的时候需要注意设定栈底元素值为-1,因为下标从0开始,故两个下标相减的时候比实际字符串长度少1,若整个串是有效的,那么就需要额外加一;若在串的首段是最长有效的括号串,那么长度也需要额外加1;当栈底元素值设为-1时这个问题就完美解决了。任何一个数减-1相当于加1。给出leetcode 解决方案,https://leetcode.com/problems/longest-valid-parentheses/。 leetcode 上是java 代码,我放上改写成python 后的代码。

#暴力遍历,找最长字串,这种方法会超时。
def longest(s):
    res = 0;
    for i in range(len(s)):
        for j in range(i,len(s)+1,2):
            if(isValid(s[i:j])):
                res = max(res,j-i);
    return res;

def isValid(s):
    temp_stack = [];
    for c in s:
        if(c == '('):
            temp_stack.append('(');
        else:
            if(temp_stack):
                temp_stack.pop();
            else:
                return False;
    if(not temp_stack):
        return True;
    else:
        return False;


#栈,左括号入栈,右括号出栈。若栈空了,说明有效串被打断,重新开始一段新串,
#否则更新串长的最大值
def longestValidParentheses(s):
        maxans = 0;
        stack = [];
        stack.append(-1);
        for i in range(len(s)):
            if (s[i] == '('):
                stack.append(i);
            else:
                stack.pop();
                if(not stack):
                    stack.append(i);
                else:
                    maxans = max(maxans, i - stack[-1]);
        return maxans;

#动态规划,最难理解的方法。
#dp 记录第i 位置时有效括号的长度
def longestValidParentheses(s: str) -> int:
        res = 0;
        dp = [0 for i in range(len(s))];
        for i in range(1,len(s)):
            if(s[i] == ')'):
                if(s[i-1] == '('):
                    dp[i] = (dp[i-2] if i>=2 else 0) + 2;
                elif(i - dp[i-1] >0 and s[i-dp[i-1]-1] == '('):
                    dp[i] = dp[i-1] + (dp[i-dp[i-1]-2] if (i-dp[i-1])>=2 else 0) + 2;
                res = max(res,dp[i]);
        return res;

#有效串以及有效串的子有效串无论从左向右扫描还是从右向左扫描其左右括号数量总是相等的,否则就是无效串。
#该思路最为巧妙,时间复杂度O(n)和空间复杂度O(1)都低.
def longestValidParentheses(s):
        left = 0;
        right = 0;
        maxlength = 0;
        for i in range(len(s)):
            if (s[i] == '('):
                left = left + 1;
            else:
                right = right + 1;
            if (left == right):
                maxlength = max(maxlength, 2 * right);
            elif (right >= left):
                left = right = 0;
               
        left = right = 0;
        for i in range(len(s)-1,-1,-1):
            if (s[i] == '('):
                left = left + 1;
            else:
                right = right + 1;
               
            if (left == right):
                maxlength = max(maxlength, 2 * left);
            elif(left >= right):
                left = right = 0;
        return maxlength;

这周就水一下吧,没啥事干。有工作或者项目介绍的欢迎留言。我目前主要从事数据分析/数据挖掘/机器学习。

猜你喜欢

转载自www.cnblogs.com/FightLi/p/10632702.html