本文最后更新于:11 天前
栈与队列相关题目。
1 概念 队列是先进先出(队头删除,队尾插入),栈是先进后出。
Go 语言中,并没有栈与队列相关的数据结构,但是我们可以借助切片来实现栈与队列的操作。
Linux 系统中,cd 这个进入目录的命令就是栈的应用。
递归的实现是栈 :每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。
1.1 用栈实现队列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 type MyQueue struct { stackIn []int stackOut []int }func Constructor () MyQueue { return MyQueue{ stackIn: make ([]int , 0 ), stackOut: make ([]int , 0 ), } }func (this *MyQueue) Push(x int ) { this.stackIn = append (this.stackIn, x) }func (this *MyQueue) Pop() int { inLen, outLen := len (this.stackIn), len (this.stackOut) if outLen == 0 { if inLen == 0 { return -1 } for i := inLen - 1 ; i >= 0 ; i-- { this.stackOut = append (this.stackOut, this.stackIn[i]) } this.stackIn = []int {} outLen = len (this.stackOut) } val := this.stackOut[outLen-1 ] this.stackOut = this.stackOut[:outLen-1 ] return val }func (this *MyQueue) Peek() int { val := this.Pop() if val == -1 { return -1 } this.stackOut = append (this.stackOut, val) return val }func (this *MyQueue) Empty() bool { return len (this.stackIn) == 0 && len (this.stackOut) == 0 }
1.2 用队列实现栈 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 type MyStack struct { queue []int }func Constructor () MyStack { return MyStack { queue: make ([]int ,0 ), } }func (this *MyStack) Push(x int ) { this.queue = append (this.queue, x) }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 }func (this *MyStack) Top() int { val := this.Pop() this.queue = append (this.queue, val) return val }func (this *MyStack) Empty() bool { return len (this.queue) == 0 }
2 题目 有效的括号。
由于栈结构的特殊性,非常适合做对称匹配类的题目。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func isValid (s string ) bool { hash := 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 ] == hash[s[i]] { stack = stack[:len (stack)-1 ] } else { return false } } return len (stack) == 0 }
逆波兰表达式求值。
题目本身不难,题解巧妙使用了 err 值得学习。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 func evalRPN (tokens []string ) int { stack := []int {} for _, token := range tokens { val, err := strconv.Atoi(token) if err == nil { stack = append (stack, val) } else { num1, num2 := stack[len (stack)-2 ], stack[(len (stack))-1 ] stack = stack[:len (stack)-2 ] switch token { case "+" : stack = append (stack, num1+num2) case "-" : stack = append (stack, num1-num2) case "*" : stack = append (stack, num1*num2) case "/" : stack = append (stack, num1/num2) } } } return stack[0 ] }
滑动窗口最大值。
构建一个递减队列来不断存储更新最大值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 func maxSlidingWindow (nums []int , k int ) []int { var queue, res []int for i := 0 ; i < k; i++ { if len (queue) > 0 { if nums[i] > queue[0 ] { queue = queue[0 :0 ] } else { for nums[i] > queue[len (queue)-1 ] { queue = queue[:len (queue)-1 ] } } } queue = append (queue, nums[i]) } res = append (res, queue[0 ]) for i := k; i < len (nums); i++ { if nums[i-k] == queue[0 ] { queue = queue[1 :] } if len (queue) > 0 { if nums[i] > queue[0 ] { queue = queue[0 :0 ] } else { for nums[i] > queue[len (queue)-1 ] { queue = queue[:len (queue)-1 ] } } } queue = append (queue, nums[i]) if len (queue) > k { queue = queue[:k] } res = append (res, queue[0 ]) } return res }
给定一个整数数组 temperatures,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。
该题使用暴力解法时间复杂度为 O(n^2),可以使用单调栈 ,空间换时间,实现 O(n) 的时间复杂度。
本题要使用递增循序(从栈头到栈底的顺序),因为只有递增的时候,栈里要加入一个元素 i 的时候,才知道栈顶元素在数组中右面第一个比栈顶元素大的元素是 i。
如果求一个元素右边第一个更大元素,单调栈就是递增的,如果求一个元素右边第一个更小元素,单调栈就是递减的 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 func dailyTemperatures (temperatures []int ) []int { var stack []int res := make ([]int , len (temperatures)) for i := 0 ; i < len (temperatures); i++ { if len (stack) == 0 { stack = append (stack, i) } else if temperatures[i] > temperatures[stack[len (stack)-1 ]] { for len (stack) > 0 && temperatures[i] > temperatures[stack[len (stack)-1 ]] { res[stack[len (stack)-1 ]] = i - stack[len (stack)-1 ] stack = stack[:len (stack)-1 ] } } stack = append (stack, i) } return res }
接雨水,单调栈参考解析 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 func trap (height []int ) int { var res int stack := []int {0 } for i := 1 ; i < len (height); i++ { if height[stack[len (stack)-1 ]] < height[i] { for len (stack) > 0 && height[stack[len (stack)-1 ]] < height[i] { top := stack[len (stack)-1 ] stack = stack[:len (stack)-1 ] if len (stack) > 0 { tmp := (min(height[stack[len (stack)-1 ]], height[i]) - height[top]) * (i - stack[len (stack)-1 ] - 1 ) res += tmp } } } else if height[stack[len (stack)-1 ]] == height[i] { stack[len (stack)-1 ] = i continue } stack = append (stack, i) } return res }func min (a, b int ) int { if a < b { return a } return b }