代码随想录day11 | 栈和队列 | 232.用栈实现队列|225. 用队列实现栈|20. 有效的括号|1047. 删除字符串中的所有相邻重复项

基础概念

队列:先进先出,跟排队一样。

栈:先进后出,后进先出,跟叠盘子和拿盘子一样。

232.用栈实现队列

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

        push(x) -- 将一个元素放入队列的尾部。
        pop() -- 从队列首部移除元素。
        peek() -- 返回队列首部的元素。
        empty() -- 返回队列是否为空。

分析:

        用两个栈来实现队列。因为队列是先进先出,而栈是先进后出,所以我们可以想到先把输入先存进栈A,然后当有需要输出的时候,把栈A的内容全部存到栈B,然后从栈B弹出。这时候就顺序就是跟队列一样了。

举个例子:有两个栈分别是stackIn和stackOut

        假设输入1、2、3,按照队列就要输出1、2、3。

        我们用栈实现就是先把1、2、3输入到stackIn、然后再从stackIn输出到stackOut。然后再输出stackOut就实现了队列。记得每次要判断和更新各自的栈顶。

所以本题代码如下:

// MyQueue 队列类
type MyQueue struct {
    stackIn  []int
    stackOut []int
}

// Constructor 队列类的构造方法
func Constructor() MyQueue {
    stackIn := make([]int, 0)
    stackOut := make([]int, 0)
    return MyQueue{stackIn, stackOut}
}

// Push 入队
func (this *MyQueue) Push(x int) {
    // 向输入栈添加元素
    this.stackIn = append(this.stackIn, x)
}

// Pop 出队
func (this *MyQueue) Pop() int {
    result := 0
    // 输出栈为空,将输入栈全部元素移到输出栈
    if len(this.stackOut) == 0 {
        for len(this.stackIn) != 0 {
            // 取出输入栈栈顶元素
            temp := this.stackIn[len(this.stackIn)-1]
            this.stackIn = this.stackIn[:len(this.stackIn)-1]   //更新stackIn的栈顶元素
            // 将从输入栈取出的元素放入输出栈
            this.stackOut = append(this.stackOut, temp) 
        }
    }
    // 取出输出栈栈顶元素
    result = this.stackOut[len(this.stackOut)-1]
    this.stackOut = this.stackOut[:len(this.stackOut)-1]    //更新stackOut的栈顶元素
    return result
}

// Peek 返回队列头元素,就是stackOut的栈顶
func (this *MyQueue) Peek() int {
    result := 0
    // 输出栈为空,将输入栈全部元素移到输出栈
    if len(this.stackOut) == 0 {
        for len(this.stackIn) != 0 {
            // 取出输入栈栈顶元素
            temp := this.stackIn[len(this.stackIn)-1]
            this.stackIn = this.stackIn[:len(this.stackIn)-1]
            // 将从输入栈取出的元素放入输出栈
            this.stackOut = append(this.stackOut, temp)
        }
    }
    // 得到输出栈栈顶元素
    result = this.stackOut[len(this.stackOut)-1]
    return result
}
// Empty 判断队空
func (this *MyQueue) Empty() bool {
    if len(this.stackIn) == 0 && len(this.stackOut) == 0 {
        return true
    }
    return false
}

扩展:

        可以看出peek()的实现,直接复用了pop(), 要不然,对stOut判空的逻辑又要重写一遍。

        再多说一些代码开发上的习惯问题,在工业级别代码开发中,最忌讳的就是 实现一个类似的函数,直接把代码粘过来改一改就完事了。

        这样的项目代码会越来越乱,一定要懂得复用,功能相近的函数要抽象出来,不要大量的复制粘贴,很容易出问题!(踩过坑的人自然懂)

        工作中如果发现某一个功能自己要经常用,同事们可能也会用到,自己就花点时间把这个功能抽象成一个好用的函数或者工具类,不仅自己方便,也方面了同事们。

        同事们就会逐渐认可你的工作态度和工作能力,自己的口碑都是这么一点一点积累起来的!在同事圈里口碑起来了之后,你就发现自己走上了一个正循环,以后的升职加薪才少不了你!哈哈哈。

225. 用队列实现栈

        请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

实现 MyStack 类:

void push(int x) 将元素 x 压入栈顶。

int pop() 移除并返回栈顶元素。

int top() 返回栈顶元素。

boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

思路:

其实这道题目就是用一个队列就够了。

        一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时在去弹出元素就是栈的顺序了。

代码如下:

        

type MyStack struct {
    queue []int//创建一个队列
}


/** Initialize your data structure here. */
func Constructor() MyStack {
    return MyStack{   //初始化
        queue:make([]int,0),
    }
}


/** Push element x onto stack. */
func (this *MyStack) Push(x int)  {
    //添加元素
    this.queue=append(this.queue,x)
}


/** Removes the element on top of the stack and returns that element. */
func (this *MyStack) Pop() int {
    n:=len(this.queue)-1//判断长度
    for n!=0{ //除了最后一个,其余的都重新添加到队列里
        val:=this.queue[0]
        this.queue=this.queue[1:]
        this.queue=append(this.queue,val)
        n--
    }
    //弹出元素
    val:=this.queue[0]
    this.queue=this.queue[1:]
    return val
    
}


/** Get the top element. */
func (this *MyStack) Top() int {
    //利用Pop函数,弹出来的元素重新添加
    val:=this.Pop()
    this.queue=append(this.queue,val)
    return val
}


/** Returns whether the stack is empty. */
func (this *MyStack) Empty() bool {
    return len(this.queue)==0
}

20. 有效的括号

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

有效字符串需满足:

1、左括号必须用相同类型的右括号闭合。​

2、左括号必须以正确的顺序闭合。

示例 1:

输入:s = "()"

输出:true

示例 2:

输入:s = "()[]{}"

输出:true

示例 3:

输入:s = "(]"

输出:false

思路:

        开始接触题目时,我们会不禁想到如果计算出左括号的数量,和右括号的数量,如果每种括号左右数量相同,会不会就是有效的括号了呢?

        事实上不是的,假如输入是 [{]},每种括号的左右数量分别相等,但不是有效的括号。这是因为结果还与括号的位置有关。

        仔细分析我们发现,对于有效的括号,它的部分子表达式仍然是有效的括号,比如 {()[()]} 是一个有效的括号,()[{}] 是有效的括号,[()] 也是有效的括号。并且当我们每次删除一个最小的括号对时,我们会逐渐将括号删除完。比如下面的例子。

        这个思考的过程其实就是栈的实现过程。因此我们考虑使用栈,当遇到匹配的最小括号对时,我们将这对括号从栈中删除(即出栈),如果最后栈为空,那么它是有效的括号,反之不是。

 代码如下:

func isValid(s string) bool {
    // 用字典事先存好括号的匹配规则
    hashmap := map[byte]byte{
        ')': '(',
        '}': '{',
        ']': '[',
    }
    // 用切片模拟栈
    stack := make([]byte, 0)
    if s == "" {
        // 空串有效
        return true
    }
    // 遍历字符串
    for i := 0; i < len(s); i++ {
        if s[i] == '(' || s[i] == '{' || s[i] == '[' {
            // 遍历字符串时遇到左括号 压栈
            stack = append(stack, s[i])
        } else if len(stack) != 0 && stack[len(stack)-1] == hashmap[s[i]] {
            // 遍历字符串时遇到右括号 栈非空且栈顶元素与该右括号匹配 弹栈
            stack = stack[:len(stack)-1]
        } else {
            // 遍历字符串时遇到左括号 栈为空或栈顶元素与该右括号不匹配 证明有右括号多余
            return false
        }
    }
    if len(stack) != 0 {
        // 遍历完了字符串,但是栈非空,证明有左括号多余
        return false
    } else {
        return true
    }
}

1047. 删除字符串中的所有相邻重复项

        给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。

        在 S 上反复执行重复项删除操作,直到无法继续删除。在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

示例: 输入:"abbaca"

输出:"ca"

解释: 例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。

提示: 1 <= S.length <= 20000 S 仅由小写英文字母组成。

思路:

        遍历字符串,先压入一个字符串到栈中,继续遍历,如果再遇到的字符串已经在栈中存在则删除掉栈中所存的.....不断这样遍历end即可

 

代码如下:

1.遍历字符串,先压入一个字符串到栈中,继续遍历,如果再遇到的字符串已经在栈中存在则删除掉栈中所存的.....不断这样遍历end即可

func removeDuplicates(s string) string {
	var stack []rune
	for _, v := range s {
		if len(stack) != 0 && v == stack[len(stack)-1] {
			stack = stack[:len(stack)-1]
			continue
		}
		stack = append(stack, v)
	}
	return string(stack)
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值