Python描述数据结构之栈实战篇

前言

  LeetCode中有关的题目。

1. LeetCode155:最小栈

  LeetCode的第155题:最小栈
  这个题基本上就是栈的基本操作,但是题目中明确指出,要设计一个能在常数时间内检索到最小元素的栈。于是乎,直接把元素放在列表里,然后min()操作一下,这样当然不行了,min()操作的时间复杂度也是 O ( n ) O(n)
  既然想到了数组,不如在入栈的时候就开始找最小值,然后把最小值放到一个数组min_list里,入栈完毕后,数组min_list里都是最小值,然后取出即可,这样时间复杂度就是 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]

  运行结果如下:

在这里插入图片描述

2. LeetCode1441:用栈操作构建数组

  LeetCode的第1441题:用栈操作构建数组
  这个题说着是栈,其实只不过是利用了栈的思想。给你一个数组list(大小由 n n 决定),利用栈的操作来实现目标数组target,如果数组list中的元素在目标数组target中,则入栈,输出 " P u s h " "Push" ,如果不在,就先入栈然后再出栈,即输出 " P u s h " , " P o p " "Push","Pop" ,这是大多数情况。还有一个特殊情况就是,如果目标数组target里面的数字是从1开始且连续的,比如 t a r g e t = [ 1 , 2 ] , n = 4 target=[1,2],n=4 ,则只需要输出 " P u s h " , " P u s h " "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"
  综上可知,入栈操作的最大次数有目标数组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

  运行结果如下:

在这里插入图片描述

3. LeetCode1021:删除最外层的括号

  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

  运行结果如下:

在这里插入图片描述

4. LeetCode682:棒球比赛

  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)

  运行结果如下:
在这里插入图片描述

5. LeetCode1047:删除字符串中的所有相邻重复项

  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)

  运行结果如下:
在这里插入图片描述

6. LeetCode496:下一个更大元素 I

  LeetCode第496题:下一个更大元素 I
  这个题的重心要放在nums2上,因为nums1nums2的一个子集,所以只需要找出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

  运行结果如下:
在这里插入图片描述

7. LeetCode20:有效的括号

  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中的notif操作:None,False,0,空字符串’’,空列表[],空字典{},空元组(),都相当于False,这个小知识点还记得吧。

  再次提醒:LeetCode官方给的几个样例都不是白给的,里面有可能包含特殊情况是我没想到的,要多思考,虽然这个题很简单,但是不细心的我在这道题吃了很大的亏(’∇’)シ┳━┳

猜你喜欢

转载自blog.csdn.net/qq_42730750/article/details/107919690