LeetCode中有关栈的题目。
LeetCode的第155题:最小栈。
这个题基本上就是栈的基本操作,但是题目中明确指出,要设计一个能在常数时间内检索到最小元素的栈。于是乎,直接把元素放在列表里,然后min()操作一下,这样当然不行了,min()操作的时间复杂度也是 O ( n ) O(n) O(n)。
既然想到了数组,不如在入栈的时候就开始找最小值,然后把最小值放到一个数组min_list里,入栈完毕后,数组min_list里都是最小值,然后取出即可,这样时间复杂度就是 O ( 1 ) O(1) O(1)了。还有一点就是,由于不知道要输入数据量的大小,所以直接用上面博客定义的顺序栈会有栈溢出的风险,所以,这里就不用指针top,而是直接用列表的基本操作来实现顺序栈。
实现代码如下:
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.S = []
self.min_list = []
def push(self, x):
self.S.append(x)
if len(self.min_list) == 0:
self.min_list.append(x)
else:
self.min_list.append(min(x, self.min_list[-1]))
def pop(self):
self.S.pop()
self.min_list.pop()
def top(self):
return self.S[-1]
def getMin(self):
return self.min_list[-1]
运行结果如下:
LeetCode的第1441题:用栈操作构建数组。
这个题说着是栈,其实只不过是利用了栈的思想。给你一个数组list(大小由 n n n决定),利用栈的操作来实现目标数组target,如果数组list中的元素在目标数组target中,则入栈,输出 " P u s h " "Push" "Push",如果不在,就先入栈然后再出栈,即输出 " P u s h " , " P o p " "Push","Pop" "Push","Pop",这是大多数情况。还有一个特殊情况就是,如果目标数组target里面的数字是从1开始且连续的,比如 t a r g e t = [ 1 , 2 ] , n = 4 target=[1,2],n=4 target=[1,2],n=4,则只需要输出 " P u s h " , " P u s h " "Push","Push" "Push","Push"即可,而不必输出 " P u s h " , " P u s h " , " P u s h " , " P o p " , " P u s h " , " P o p " "Push","Push","Push","Pop","Push","Pop" "Push","Push","Push","Pop","Push","Pop"。
综上可知,入栈操作的最大次数有目标数组target里面最大的数字决定,代码实现如下:
def buildArray(target, n):
result = []
for num in list(range(1, max(target) + 1)):
if num in target:
result.append('Push')
else:
result.append('Push')
result.append('Pop')
return result
运行结果如下:
LeetCode的第1021题:删除最外层的括号。
这个题我没有用栈(数组),大致思路就是用一个flag来表示匹配的括号是否完全闭合,如果完全闭合,则将temp里匹配到的字符放入到result里。代码如下:
def removeOuterParentheses(S):
flag = 0
temp = ''
result = ''
for s in S:
if s == '(':
flag += 1
temp += s
else:
flag -= 1
temp += s
if flag == 0:
result += temp[1:-1]
temp = ''
del flag
del temp
return result
运行结果如下:
LeetCode第682题:棒球比赛。
这个题就是遍历一遍就可以了,这里定义一个栈(数组),如果字符是C,则删除栈里面的最后一个;如果字符是D,则将栈里面最后一个数字乘以2再入栈;如果字符是+,则将栈里面最后一个数字和倒数第二个数字相加,然后再入栈;最后将栈里面的所有数字求和,返回结果。代码如下:
def calPoints(ops):
result = []
for s in ops:
if s == 'C':
result.pop()
elif s == 'D':
result.append(2 * result[-1])
elif s == '+':
result.append(result[-1] + result[-2])
else:
result.append(int(s))
return sum(result)
LeetCode第1047题:删除字符串中的所有相邻重复项。
这个题应该很快就能想到用栈来解决,大致思路就是,先入栈,如果接下来要入栈的字符与栈里面最后一个字符相同,则这个字符不执行入栈操作,并将栈里面最后一个字符进行出栈操作删除,最后将栈里面的字符转成字符串返回。代码如下:
def removeDuplicates(S):
stack = []
for s1 in S:
if not stack:
stack.append(s1)
else:
if s1 == stack[-1]:
stack.pop()
else:
stack.append(s1)
return ''.join(stack)
LeetCode第496题:下一个更大元素 I。
这个题的重心要放在nums2上,因为nums1是nums2的一个子集,所以只需要找出nums2每个数字右边的第一个最大值即可,然后用字典存储它们的关系,最后再通过遍历nums1每个数字在字典中对应的值即可。
通过一个栈来找出nums2每个数字右边的第一个最大值,大致思路就是,先判断栈是否为空,如果不为空,说明栈里面的元素还没有找到它右边的第一个最大值;如果后面的数字大于前面的数字,则将栈里面的数字进行出栈操作,直至栈为空,然后再将这个元素入栈;如果后面的数字小于前面的数字,则将其直接入栈。代码如下:
def nextGreaterElement(nums1, nums2):
stack = []
dict1 = {}
result = []
for num in nums2:
# 这个while循环就是找到入栈的元素的右边的第一个最大值
while stack and num > stack[-1]:
dict1[stack[-1]] = num
stack.pop()
stack.append(num)
del stack
for x in nums1:
result.append(dict1.get(x, -1))
return result
LeetCode第20题:有效的括号。
这个题粗略一看感觉和上面第三个题差不多,我也是这样想的,用计数的方式来表示是否匹配,然后就这么提交了。enmmmm,没错,解答错误,因为字符(]这种情况上述的方法就失效了,所以就好好用栈来解决吧。
大致就是,如果是左括号就入栈,是右括号就出栈,如果出栈的括号与匹配的括号是同一种,则继续匹配,否则直接返回False;最后如果栈为空,说明已匹配完毕,返回True,否则就返回False。代码如下:
def isValid(s):
stack = []
for s1 in s:
if s1 == '(' or s1 == '[' or s1 == '{':
stack.append(s1)
else:
try:
if (s1 == ')' and stack.pop() == '(') or (s1 == ']' and stack.pop() == '[') or (s1 == '}' and stack.pop() == '{'):
continue
else:
return False
except Exception as err:
return False
if len(stack) == 0:
return True
else:
return False
上面的代码有些长,现在简化一下,代码如下:
def isValid1(s):
dict1 = {')': '(', ']': '[', '}': '{'}
stack = []
for s1 in s:
if s1 not in dict1:
stack.append(s1)
else:
temp = stack.pop() if stack else None
if temp == dict1.get(s1):
continue
else:
return False
return not stack
对于Python中的not,if操作:None,False,0,空字符串’’,空列表[],空字典{},空元组(),都相当于False,这个小知识点还记得吧。
再次提醒:LeetCode官方给的几个样例都不是白给的,里面有可能包含特殊情况是我没想到的,要多思考,虽然这个题很简单,但是不细心的我在这道题吃了很大的亏(’∇’)シ┳━┳