算法练习-第十一天【栈与队列】
栈与队列
232.用栈实现队列
思路
一道模拟题,不涉及到算法部分。如果想用栈来实现队列,至少需要2个栈,一个输入栈一个输出栈。
- 在进行
push
操作时,将数据放入到输入栈中。 - 在进行
pop
操作时,将数据从输出栈中取出,如果输出栈为空时,则将输入栈的数据全部放入输出栈。 - 如果输入栈和输出栈都为空,则队列为空。
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
}
总结
在实际代码书写过程中,因为pop
和peek
实现的功能类似,因为在peek
方法中,可以调用pop
的方法,然后将pop
出来的数据再插入回输出栈。
225.用队列实现栈
思路
使用双队列
- 队列
queue1
进行入队操作 - 当执行
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种情况考虑:
- 遍历匹配的过程中,左括号没有了,但还有右括号,不匹配
- 遍历匹配的过程中,左括号与右括号的类型不同,不匹配
- 遍历结束后,左括号有剩余,说明左括号多于右括号,不匹配
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. 删除字符串中的所有相邻重复项
思路
删除相邻重复的字符就是需要知道当前的字符与前一位是否相同,如果相同则一起消除,有点类似于消消乐。
- 遍历字符串的过程中,需要记录已经遍历的字符,并将前一位访问过的字符与当前字符做比对。栈的数据结构刚好满足此操作。
- 使用字符数组模拟栈的操作,当栈不为空时,将栈顶字符与当前做比对,如果相同则弹出。不相同则将当前字符加入栈中,继续遍历操作。最后栈内剩余的字符就是未消除的字符
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)
}
总结
与括号匹配比较类似的一道题,此题需要做的是消除相邻重复的字符,使用栈就可以轻松解决。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构