Leetcode 学习之旅 (一) 栈篇

本人比较菜,只是用这个记录下自己的学习经历,非计算机专业,没有系统的学习过算法以及数据结构。有什么错误的,请指正,勿喷。
代码使用python进行编写,很多也是借鉴了官网和评论的设计思路。这里只是进行记录学习的过程。
题库的学习是按照类型来划分的。比较适合初学者理解。

栈就是一种线性表,简单的理解就是先进后出。先放进去的数据,只能最后拿出来。(这只是一般的运用)
这个概念比较好理解,我们直接来看题。

20.有效的括号

题目

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 注意空字符串可被认为是有效字符串。

示例 1:

输入: “()” 输出: true
示例 2:
输入: “()[]{}” 输出: true
示例 3:
输入: “(]” 输出: false
示例 4:
输入: “([)]” 输出: false
示例 5:
输入: “{[]}” 输出: true

题目分析
首先,这是一道非常直观,可以使用栈思维来解决的算法问题,主要就是配对,左括号和右括号的配对。

我们先设置一个栈来存储数据,然后开始遍历整个输入。

算法的最基础的思想就是遇到左括号就放入到栈中(等待配对),而遇到右括号的话,开始判断栈顶的元素是否与该输入配对,配对则弹出栈顶元素,然后继续遍历,否则直接返回错误。

这就是最简单的栈思路。

下面放代码

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

        stack = []
        for s1 in s:
            if s1 == '(' or s1 == '{' or s1 == '[':
                stack.append(s1)
            elif(len(stack)!=0 and ( (s1 == ')' and stack[-1] == '(') or (s1 == ']' and stack[-1] == '[') or ( s1 == '}' and stack[-1] == '{'))):
                    stack.pop()
            else:
                return False
            
        return True if len(stack) == 0 else False

整个代码还是很简单的,我们还需要对空栈这个特殊情况进行判定,还是很好理解的。

225.用队列实现栈

题目

使用队列实现栈的下列操作:

push(x) – 元素 x 入栈 pop() – 移除栈顶元素 top() – 获取栈顶元素 empty() – 返回栈是否为空
注意:
你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty
这些操作是合法的。 你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 ,
只要是标准的队列操作即可。 你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。

题目分析
个人觉得这是一个非常经典的题目。队列和栈的区别就在于,队列是先进先出的规则来存放数据的.

方法一: 一个队列 复杂度:(压入-O(n) , 弹出-O(1))

我们肯定要在初始化函数中定义一个栈,然后开始编写栈的push pop top empty 这四个操作函数.

push() 函数的编写
首先我们举个例子.
栈中的数据 从栈底到栈顶是
1 2 3 4 5
那么出栈的顺序就是
5 4 3 2 1
这个很好理解,但我们是以队列的方式来实现这个栈的,那么正常的pop()顺序是
1 2 3 4 5
这两者是相反的.那么最简单的想法是我们在存储数据的过程中,人为地将队列中数据的顺序调换,那么队列输出的顺序,就是栈的出栈顺序,这就实现了用队列实现栈的操作.

我们假设队列中的数据是 1 2 3 4 5
此时我想将数字6压入栈内,那么我可以将6放入到队列的尾部,但是如果想要进行弹栈的操作,那么按照队列的逻辑,应该是数字1被弹出,而栈的逻辑是最近压入的数字6应该被弹出,所以最新的数字6应该在队列的首部,而不应该是尾部.

那么我们应该将队列中的数据整个反转.
6 5 4 3 2 1
同理,插入 7
6 5 4 3 2 1 7
反转前几个数据
7 6 5 4 3 2 1

实现这个操作的方法就是将原本的数据放入到新数据后面.
那么队列的首部就变成了栈顶.

具体代码

def push(self, x):
    """
    Push element x onto stack.
    :type x: int
    :rtype: None
    """
    # 把一个数据放入到队列中
    self.q.put(x)
    # 反转队列内容, 除最后一个外,把前面的提到后面去
    for _ in range(self.q.qsize() - 1): 
        self.q.put(self.q.get())

pop() 函数的编写
这个直接就是把队列的首部提取出来就行.

def pop(self):
    """
    Removes the element on top of the stack and returns that element.
    :rtype: int
    """
    return self.q.get()

top() 函数的编写
返回栈顶元素,也是队列首部的元素

def top(self):
    """
    Get the top element.
    :rtype: int
    """
    r = self.q.get()
    self.q.put(r)
    for _ in range(self.q.qsize() - 1):
        self.q.put(self.q.get())
    return r

这种方法就是把队列的顺序,直接反序.

方法二: 一个队列 复杂度:(压入-O(n) , 弹出-O(1))

这个方法就是使用两个队列,队列1正常地存储数据,队列二则是保存队列一的反向数据.

初始化函数的编写

这里直接定义两个队列,q1存储正常的数据,q2是用来临时存储

def __init__(self):
    """
    Initialize your data structure here.
    """
    # 定义一个队列
    self.q1 = Queue()
    self.q2 = Queue()
    self.top1 = 0

push()函数的编写

def push(self, x):
    """
    Push element x onto stack.
    :type x: int
    :rtype: None
    """
    # 把一个数据放入到队列中
    self.q1.put(x)
    self.top1 = x

pop()函数的编写
删除最新增加的数据

  def pop(self):
        while(self.q1.qsize()>1):
            self.top1 = self.q1.get()
            self.q2.put(self.top1)
        
        # q1只剩下最新的元素 
        
        res = self.q1.get() #得到最新的数据

        temp = Queue()
        temp = self.q1
        self.q1 = self.q2
        self.q2 = temp

        return res

top和 empty 函数的编写就不赘婿了.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
引用\[1\]提供了一个朴素的解法,使用两个来存储字符串,一个用来存储普通字符,另一个用来存储特殊字符。遍历字符串,如果是普通字符则压入第一个,如果是特殊字符则弹出第一个顶元素。最后比较两个是否相同即可判断字符串是否有效。这个解法的时间复杂度是O(M + N),空间复杂度也是O(M + N)。\[1\] 引用\[2\]提供了另一个的应用场景,即判断括号是否有效。遍历字符串,如果是左括号则压入,如果是右括号则判断和顶元素是否匹配,不匹配则返回false,匹配则弹出顶元素。最后判断是否为空即可判断括号是否有效。\[2\] 引用\[3\]也提供了一个判断括号是否有效的解法,使用来操作。遍历字符串,如果是左括号则压入,如果是右括号则判断和顶元素是否匹配,不匹配则返回false,匹配则弹出顶元素。最后判断是否为空即可判断括号是否有效。这个解法使用了HashMap来存储括号的对应关系。\[3\] 综上所述,在解决字符串相关问题中有着广泛的应用,包括判断字符串是否有效、逆波兰表达式等。在解决这些问题时,可以帮助我们保存和处理字符的顺序,从而简化问题的处理过程。 #### 引用[.reference_title] - *1* *3* [Leetcode刷题03-](https://blog.csdn.net/weixin_47802917/article/details/123007699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v4^insert_chatgpt"}} ] [.reference_item] - *2* [leetCode-类型详解](https://blog.csdn.net/zhiyikeji/article/details/125508011)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v4^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值