栈
栈是一种特殊的数据结构,只能在一端进行插入和删除操作。栈的特点是后进先出(LIFO,Last In First Out),也就是最后进入的元素最先被处理。
栈的应用场景
- 表达式求值
例如:将1 + 2 * (4 + 6 / 2 - 1) + 4 这个中缀表达式转化为:1 2 4 6 2 / + 1 - * + 4 + 这个后缀表达式
-
函数调用
发生函数调用时,调用函数(caller)的状态被保存在栈内,被调用函数(callee)的状态被压入调用栈的栈顶。在函数调用结束时,栈顶的函数(callee)状态被弹出,栈顶恢复到调用函数(caller)的状态。
-
系统调用
- 递归调用
- 二叉树遍历、图的深度搜索
232. 用栈实现队列
解题思路:
- 栈的特点是后进先出,那么我们再操作一次压栈,栈底的元素就可以被移到栈顶,达到先进先出的效果
- 两个栈,一个栈记录了压栈的操作,一个栈负责实现出栈
type MyQueue struct {
inStack, outStack []int
}
func Constructor() MyQueue {
return MyQueue{}
}
func (this *MyQueue) Push(x int) {
this.inStack = append(this.inStack, x)
}
func (this *MyQueue) in2out() {
for len(this.inStack) > 0 {
this.outStack = append(this.outStack, this.inStack[len(this.inStack) - 1])
this.inStack = this.inStack[:len(this.inStack) - 1]
}
}
func (this *MyQueue) Pop() int {
if len(this.outStack) == 0 {
this.in2out()
}
x := this.outStack[len(this.outStack)-1]
this.outStack = this.outStack[:len(this.outStack)-1]
return x
}
func (this *MyQueue) Peek() int {
if len(this.outStack) == 0 {
this.in2out()
}
return this.outStack[len(this.outStack) - 1]
}
func (this *MyQueue) Empty() bool {
return len(this.inStack) == 0 && len(this.outStack) == 0
}
20. 有效的括号
解题思路:
给我们一个这样的字符串,人脑的做法一般是根据左括号一个个去匹配。但是这样比较累,括号多了以后看不过来,而且括号可以嵌套。
那么我们反过来看,把'('压入栈,出现')'就从栈里弹出一个来。如果没有可以和右括号匹配的元素那么就是无效的括号。
无效的括号判断条件
- 右括号不匹配
- 栈为空
- 栈弹出的元素不是期望元素
- 左括号不匹配(字符串遍历完了栈不为空,没有找到与之匹配字符)
func isValid(s string) bool {
n := len(s)
// 如果字符长度为奇数,肯定不匹配
if n % 2 == 1 {
return false
}
stack := []byte{}
pairs := map[byte]byte{
')': '(',
']': '[',
'}': '{',
}
for i := range s {
if pairs[s[i]] > 0 {
if len(stack) == 0 || stack[len(stack)-1] != pairs[s[i]] {
return false
}
// 出栈
stack = stack[:len(stack) - 1]
} else {
// 压入栈
stack = append(stack, s[i])
}
}
return len(stack) == 0
}