前言
马上要面临毕业找工作,对于计算机专业的学生来说,刷LeetCode是必经一步,一是为了应对专业笔试题,二是复习数据结构、算法的相关知识,对于面试也有好处,现在开此专栏记录自己的刷题过程。在正式开始刷题之前,在网上看了好多诸如“如何正确打开LeetCode”之类的文章经验,其中lucifer(知乎用户)总结的十分详细,而且给出比较完整的进阶路线,所以这里跟着大佬的脚步,把大佬总结的经典题目先过一遍,附上大佬的Github。
1、有效的括号(Valid Parentheses)
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。示例 1:
输入: "()"
输出: true示例 2:
输入: "()[]{}"
输出: true示例 3:
输入: "(]"
输出: false示例 4:
输入: "([)]"
输出: false示例 5:
输入: "{[]}"
输出: true
题目就是判断给定的只包含 '(',')','{','}','[',']' 的字符串,是否为有效字符串,即所有的括号都可以按照规则组合。
解法一:
初看到这个题目,一个比较直观的想法就是,第一个有效的组合(即两个字符正确组成括号)一定是紧邻的两个字符。如果出现这样的组合,我将其从字符串中删掉,之后第二个有效组合也一定是紧邻的两个字符,以此类推,按照这样的方式判断,只需要判断相邻的两个字符是否构成有效组合(说的比较绕,可以结合具体例子理解)。
所以第一种解法(我的最初解法):从左到右读取这个字符串,每次读取的字符存储到一个list当中,当list的长度大于等于2的时候,就判断list中最新进入的两个字符能否构成一个有效的组合(正确组成括号),如果构成有效的组合,就从list中删去,如果不能构成有效组合,就继续读取。当遍历完这个字符串之后,如果是有效字符串,那么所有的括号都可以正确组合,所以list长度最终为0;否则list长度不为0,表示不是有效字符串。代码如下:
class Solution(object):
def isValid(self, s):
"""
:type s: str
:rtype: bool
"""
s_list = list(s)
temp = []
for i in range(len(s_list)):
temp.append(s_list[i])
if len(temp) > 1:
isDelete = self.isSame(temp[-2],temp[-1])
if isDelete:
_ = temp.pop()
_ = temp.pop()
if len(temp) == 0:
return True
else:
return False
def isSame(self, c_left, c_right):
if (c_left == '(' and c_right == ')') or (c_left == '{' and c_right == '}') or (c_left == '[' and c_right == ']'):
return True
else:
return False
逻辑是正确的,不过在代码实现的时候,遇到一个问题还是记录一下。因为每次如果两个相邻的字符可以正确组合,那需要从List中删除。python删除list中的元素有三种方式:
1、remove()
remove(parameter) 函数用于移除列表中某个值的第一个匹配项。其中,parameter为元素值。
aList = [123, 'xyz', 'zara', 'abc', 'xyz'];
aList.remove('xyz'); # aList = [123, 'zara', 'abc', 'xyz'];
2、pop()
pop(parameter)函数用于移除list中指定索引位置的元素。其中,parameter为索引值,如果为空默认删除list中最后一个元素。
aList = [123, 'xyz', 'zara', 'abc', 'xyz'];
top_element = aList.pop(1);
# top_element = 'xyz'
# aList = [123, 'zara', 'abc', 'xyz'];
3、del()
del[索引数] 函数删除指定索引数的元素,还可以用来删除整个list;但是del是python语句,而不是列表方法,无法通过list来调用。
aList = [123, 'xyz', 'zara', 'abc', 'xyz'];
del aList[1];
# aList = [123, 'zara', 'abc', 'xyz'];
最开始实现的时候,在删除元素部分,也就是代码14、15行,使用的是remove(temp[-1]),导致bug,排查了好久o(╯□╰)o。
解法二:
官方的解法,使用栈的思想(后进先出),因为在进行判断是否构成正确组合的时候,触发条件是当读取到闭括号的时候;所以解法的流程如下:
- 初始化一个空栈
- 遍历字符串,如果是开括号,进栈;如果是闭括号,栈顶元素出栈,且判断是否与当前读取到的元素构成括号;如果构成,接着读取字符串中的下一字符;如果不构成括号,返回False。
- 字符串遍历完毕,如果栈为空,则为有效字符串;否则为无效字符串。
代码部分如下:
class Solution(object):
def isValid(self, s):
"""
:type s: str
:rtype: bool
"""
stack = []
# 右括号作为key;左括号作为value
mapping = {')':'(','}':'{',']':'['}
for char in s:
# 如果是右括号进栈;取栈顶元素进行匹配
if char in mapping:
top_element = stack.pop() if stack else '#'
if mapping[char] != top_element:
return False
# 如果是左括号,直接进栈
else:
stack.append(char)
return not stack
复杂度分析:
时间复杂度:O(n),因为我们一次只遍历给定的字符串中的一个字符并在栈上进行 O(1) 的推入和弹出操作。
空间复杂度:O(n),当我们将所有的开括号都推到栈上时以及在最糟糕的情况下,我们最终要把所有括号推到栈上。例如 ((((((((((。
解法三:
在评论区还看到一个更为简便的代码,所谓简便是指代码量少,简洁易懂;不过在执行的时候,在LeetCode上面超出时间限制。
不过能想出这样的解法,也足以说明其对python的熟练程度以及对问题的深刻理解,代码如下:
class Solution(object):
def isValid(self, s):
"""
:type s: str
:rtype: bool
"""
while "()" in s or "{}" in s or "[]" in s:
s.replace("()","")
s.replace("{}","")
s.replace("[]","")
return s==""