算法练习-第十一天【栈与队列】

栈与队列

232.用栈实现队列

参考:代码随想录

思路

一道模拟题,不涉及到算法部分。如果想用栈来实现队列,至少需要2个栈,一个输入栈一个输出栈。

  1. 在进行push操作时,将数据放入到输入栈中。
  2. 在进行pop操作时,将数据从输出栈中取出,如果输出栈为空时,则将输入栈的数据全部放入输出栈。
  3. 如果输入栈和输出栈都为空,则队列为空。
type MyQueue struct {
	stackIn, stackOut []int
}

func Constructor() MyQueue {
	return MyQueue{}
}

func (q *MyQueue) Push(x int) {
	q.stackIn = append(q.stackIn, x)
}

func (q *MyQueue) in2out() {
	n := len(q.stackIn)
	for i := n - 1; i >= 0; i-- {
		q.stackOut = append(q.stackOut, q.stackIn[i])
		q.stackIn = q.stackIn[:i]
	}
}

func (q *MyQueue) Pop() int {
	if len(q.stackOut) == 0 {
		q.in2out()
	}
	x := q.stackOut[len(q.stackOut)-1]
	q.stackOut = q.stackOut[:len(q.stackOut)-1]
	return x
}

func (q *MyQueue) Peek() int {
	x := q.Pop()
	q.stackOut = append(q.stackOut, x)
	return x
}

func (q *MyQueue) Empty() bool {
	return len(q.stackIn) == 0 && len(q.stackOut) == 0
}

总结

在实际代码书写过程中,因为poppeek实现的功能类似,因为在peek方法中,可以调用pop的方法,然后将pop出来的数据再插入回输出栈。

225.用队列实现栈

参考:代码随想录

思路

使用双队列

  1. 队列queue1进行入队操作
  2. 当执行pop操作时,需要将queue1中的数据除了第0个元素外,都添加到queue2中进行备份,然后弹出queue1的第0个元素。接下来执行将queue2的队列赋值给queue1,即:queue1=queue2,清空queue2队列。
type MyStack struct {
	queue1 []int
	queue2 []int
}

func Constructor() MyStack {
	return MyStack{
		queue1: make([]int, 0),
		queue2: make([]int, 0),
	}
}

func (s *MyStack) Push(x int) {
	s.queue1 = append(s.queue1, x)
}

func (s *MyStack) Pop() int {
	for n := len(s.queue1) - 1; n > 0; n-- {
		s.queue2 = append(s.queue2, s.queue1[0])
		s.queue1 = s.queue1[1:]
	}
	val := s.queue1[0]
	s.queue1 = s.queue1[1:]
	s.queue1, s.queue2 = s.queue2, s.queue1

	return val
}

func (s *MyStack) Top() int {
	val := s.Pop()
	s.queue1 = append(s.queue1, val)

	return val
}

func (s *MyStack) Empty() bool {
	return len(s.queue1) == 0
}

/**
 * Your MyStack object will be instantiated and called as such:
 * obj := Constructor();
 * obj.Push(x);
 * param_2 := obj.Pop();
 * param_3 := obj.Top();
 * param_4 := obj.Empty();
 */

优化

使用一个队列完成栈的模拟操作,当需要弹出栈顶时,将队列中的前n-1个元素全部放入到队列的尾部,那么队列出队时第1个元素就是栈顶。

type MyStack struct {
	queue []int
}

func Constructor() MyStack {
	return MyStack{
		queue: make([]int, 0),
	}
}

func (s *MyStack) Push(x int) {
	s.queue = append(s.queue, x)
}

func (s *MyStack) Pop() int {
	for n := len(s.queue) - 1; n > 0; n-- {
		s.queue = append(s.queue, s.queue[0])
		s.queue = s.queue[1:]
	}
	val := s.queue[0]
	s.queue = s.queue[1:]

	return val
}

func (s *MyStack) Top() int {
	val := s.Pop()
	s.queue = append(s.queue, val)

	return val
}

func (s *MyStack) Empty() bool {
	return len(s.queue) == 0
}

/**
 * Your MyStack object will be instantiated and called as such:
 * obj := Constructor();
 * obj.Push(x);
 * param_2 := obj.Pop();
 * param_3 := obj.Top();
 * param_4 := obj.Empty();
 */

总结

使用队列模拟栈的操作,可以利用单队列的方式完成。每次pop操作将队列头部的元素(不包括最后一个元素)放到队列的尾部重新加入队列,此时弹出的第0个元素就是栈顶的元素,然后再移除第0个元素。

20. 有效的括号

参考:代码随想录

思路

匹配括号的问题分3种情况考虑:

  1. 遍历匹配的过程中,左括号没有了,但还有右括号,不匹配
  2. 遍历匹配的过程中,左括号与右括号的类型不同,不匹配
  3. 遍历结束后,左括号有剩余,说明左括号多于右括号,不匹配
func isValid(s string) bool {
	if s == "" || len(s)%2 == 1 {
		return false
	}
	m := map[byte]byte{
		'(': ')',
		'[': ']',
		'{': '}',
	}
	stack := []byte{}
	for i := 0; i < len(s); i++ {
		if s[i] == '(' || s[i] == '[' || s[i] == '{' {
			// 遇到左括号 就将其放入到栈中
			stack = append(stack, m[s[i]])
		} else if len(stack) != 0 && stack[len(stack)-1] == s[i] {
			// 当前的字符与栈顶的相同,则出栈。  即匹配了右括号
			stack = stack[:len(stack)-1]
		} else {
            //情况1: 遍历的过程中,栈为空,说明右括号没有与之匹配的左括号,返回false
            //情况2: 遍历过程中,右括号与栈中的左括号不匹配,则返回false
			return false
		}
	}
    //情况3: 匹配完之后有剩余,则是false, 说明左括号多了
	return len(stack) == 0
}

总结

括号匹配问题大部分都是通过栈来解决的。

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

参考:代码随想录

思路

删除相邻重复的字符就是需要知道当前的字符与前一位是否相同,如果相同则一起消除,有点类似于消消乐。

  1. 遍历字符串的过程中,需要记录已经遍历的字符,并将前一位访问过的字符与当前字符做比对。栈的数据结构刚好满足此操作。
  2. 使用字符数组模拟栈的操作,当栈不为空时,将栈顶字符与当前做比对,如果相同则弹出。不相同则将当前字符加入栈中,继续遍历操作。最后栈内剩余的字符就是未消除的字符
func removeDuplicates(s string) string {
	if len(s) == 1 {
		return s
	}
	stack := make([]byte, 0)
	for i := 0; i < len(s); i++ {
		if len(stack) > 0 && stack[len(stack)-1] == s[i] {
			stack = stack[:len(stack)-1]
		} else {
			stack = append(stack, s[i])
		}
	}

	return string(stack)
}

总结

与括号匹配比较类似的一道题,此题需要做的是消除相邻重复的字符,使用栈就可以轻松解决。

posted @   neil_liu  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示