4月30天leetcode训练-Day16

本文探讨了如何判断包含括号和星号的字符串是否有效,提供了四种不同的算法解法,包括使用双栈、双向扫描、递归和一种高级算法。

Day16:Valid Parenthesis String

问题描述:

给定一个仅包含三种类型的字符的字符串:'('')''*',编写一个函数来检查此字符串是否有效。我们通过以下规则定义字符串的有效性:
任何左括号'('必须具有对应的右括号')'。
任何右括号')'必须具有对应的左括号'('。
左括号'('必须位于相应的右括号')'之前。
'*'可被视为单个右括号')'或单个左括号'('或一个空字符串。空字符串也是有效的。

Example:

Example 1:

Input: "()"
Output: True

Example 2:

Input: "(*)"
Output: True

Example 3:

Input: "(*))"
Output: True

解法一:

设置双栈,左括号栈和start栈
遇到左括号,将左括号的位置放入左栈中,
遇到*,将*的位置放入start栈中
如果遇到右括号,则从左括号栈中顶出一个,若左括号栈为空,则从start栈中顶出一个,若start栈也为空,则返回False
遍历一遍后,若左括号栈不为空,且start栈为空,则返回false
若左括号栈不为空,且start栈不为空,则在依次遍历这两个栈,依次顶出一个元素,若start栈的位置在左括号栈之前则返回False。
在上述遍历也完成后,若左括号栈还是有元素则说明左括号多了,返回False,否则返回True.

class Solution:
    def checkValidString(self, s: str) -> bool:
        for i in range(len(s)):
            print(i)
            print(left,start)
            if s[i] == '(':
                left.append(i)
            elif s[i] == '*':
                start.append(i)
            else:
                if len(left) == 0 and len(start) == 0:
                    return False
                if len(left) != 0:
                    left.pop()
                else:
                    start.pop()
        while(len(left) != 0 and len(start) !=0):
            l = left.pop()
            s = start.pop()
            if l > s:
                return False
        return len(left) == 0

时间复杂度为O(n),空间复杂度为O(N).

解法二:

设置左右两个变量left,right,遍历两次字符串。第一次正向遍历:将认为是‘(’,所以如果遇到和‘(’则left 加1,否则减1,若在过程中left 小于0,则返回false,遍历结束后,若left = 0,则返回True,否则left > 0,还需要进行反向遍历,因为有可能多余的‘(’是‘’,所以反向遍历:这次将‘’认为是‘)’,对right变量的操作跟之前一样,最后若right >= 0 返回True.因为大于0和之前的left > 0对应上了,说明有多余的*,*可以认为是空字符。

class Solution:
    def checkValidString(self, s: str) -> bool:
        left , right = 0,0
        for i in range(len(s)):
            if s[i] == '(' or s[i] == '*':
                left += 1
            else:
                left -= 1
            if left < 0:
                return False
        if left == 0:
            return True
        for i in range(len(s) -1 , -1 ,-1):
            if s[i] == ')' or s[i] == '*':
                right += 1
            else:
                right -= 1
            if right < 0:
                return False
        return True

时间复杂度为O(n),空间复杂度为O(1).

解法三:

暴力破解,递归方法,设置辅助函数,里面参数有当前递归开始的位置,以及当前左括号的个数,从当前位置开始遍历字符串,如果遇到左括号则记录变量加1,如果遇到右括号且记录变量大于0,则记录变量减1,否则返回false,如果遇到*,则从下一个位置开始新的递归,将*作为左括号,右括号,和空的情况都遍历到,将这三种情况通过or连接起来,只要有一种情况是True就行,最后看记录变量是否为0.
不过这种算法复杂度太高,leetcode好像不通过。

class Solution:
    def checkValidString(self, s: str) -> bool:
        return self.helper(s,0,0)
    def helper(self,s,start,count):
        if count < 0:
            return False
        for i in range(start,len(s)):
            if s[i] == '(':
                count += 1
            elif s[i] == ')':
                if count > 0:
                    count -= 1
                else:
                    return False
            else:
                return self.helper(s,i+1,count) or self.helper(s,i + 1,count + 1) or self.helper(s,i + 1,count - 1)
        return count == 0

解法四:

还有一种解法,据说是论坛上第一的算法,但是我还没怎么看懂,所以先贴出来别人的解析链接,留待后续再看。

https://www.cnblogs.com/grandyang/p/7617017html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值