Week 17 @ 2025 算法周记【单调队列 + 单调栈】
单调队列
LC 239. Sliding Window Maximum 滑动窗口最大值
https://leetcode.com/problems/sliding-window-maximum/description/
func maxSlidingWindow(nums []int, k int) []int {
q := NewMonotonicQueue()
result := make([]int, 0, len(nums))
for i := 0; i < k; i++ {
q.Push(nums[i])
}
result = append(result, q.Max())
for i := k; i < len(nums); i++ {
q.Push(nums[i])
q.Pop(nums[i-k])
result = append(result, q.Max())
}
return result
}
type MonotonicQueue struct {
l *list.List
}
func NewMonotonicQueue() *MonotonicQueue {
return &MonotonicQueue {
l: list.New(),
}
}
func (q *MonotonicQueue) Push(x int) {
for {
back := q.l.Back()
if back == nil || back.Value.(int) >= x {
break
}
q.l.Remove(back)
}
q.l.PushBack(x)
}
func (q *MonotonicQueue) Pop(x int) {
front := q.l.Front()
if front.Value == x {
q.l.Remove(front)
}
}
func (q *MonotonicQueue) Max() int {
return q.l.Front().Value.(int)
}
单调栈
LC 1019. Next Greater Node In Linked List 链表中的下一个更大节点
https://leetcode.com/problems/next-greater-node-in-linked-list/description/
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func nextLargerNodes(head *ListNode) []int {
values := toValues(head)
n := len(values)
result := make([]int, n)
stack := make([]int, 0, n)
for i := n-1; i >= 0; i-- {
for len(stack) > 0 && stack[len(stack)-1] <= values[i] {
stack = stack[:len(stack)-1]
}
if len(stack) > 0 {
result[i] = stack[len(stack)-1]
}
stack = append(stack, values[i])
}
return result
}
func toValues(head *ListNode) []int {
values := make([]int, 0, 1_0000)
for head != nil {
values = append(values, head.Val)
head = head.Next
}
return values
}
LC 1944. Number of Visible People in a Queue 队列中可以看到的人数
https://leetcode.com/problems/number-of-visible-people-in-a-queue/description/
func canSeePersonsCount(heights []int) []int {
result := make([]int, len(heights))
stack := make([]int, 0, len(heights))
for i := len(heights) - 1; i >= 0; i-- {
count := 0
for len(stack) > 0 && stack[len(stack)-1] < heights[i] {
stack = stack[:len(stack)-1]
// 统计到「下一个等高或更高元素之间」有几个元素(已剔除被遮挡元素)
count++
}
if len(stack) > 0 {
result[i] = count + 1 // 也能看到「下一个等高或更高元素」
} else {
result[i] = count
}
stack = append(stack, heights[i])
}
return result
}
LC 1475. Final Prices With a Special Discount in a Shop 商品折扣后的最终价格
https://leetcode.com/problems/final-prices-with-a-special-discount-in-a-shop/description/
func finalPrices(prices []int) []int {
n := len(prices)
result := make([]int, n)
stack := make([]int, 0, n)
for i := n-1; i >= 0; i-- {
// 找到下一个更小或相等元素
for len(stack) > 0 && stack[len(stack)-1] > prices[i] {
stack = stack[:len(stack)-1]
}
if len(stack) > 0 {
result[i] = prices[i] - stack[len(stack)-1]
} else {
result[i] = prices[i]
}
stack = append(stack, prices[i])
}
return result
}
LC 901. Online Stock Span 股票价格跨度
https://leetcode.com/problems/online-stock-span/description/
type StockSpanner struct {
stack []Value
day int
}
type Value struct {
price int
index int
}
func Constructor() StockSpanner {
return StockSpanner{
day: -1,
}
}
func (this *StockSpanner) Next(price int) int {
// 向前找 > 当前值的 index === 栈内剔除 <= 当前值的元素
for len(this.stack) > 0 && this.stack[len(this.stack)-1].price <= price {
this.stack = this.stack[:len(this.stack)-1]
}
this.day++
var result int
if len(this.stack) > 0 {
lastDayIndex := this.stack[len(this.stack)-1].index
result = this.day - lastDayIndex
} else {
result = this.day + 1
}
this.stack = append(this.stack, Value{price, this.day})
return result
}
/**
* Your StockSpanner object will be instantiated and called as such:
* obj := Constructor();
* param_1 := obj.Next(price);
*/
LC 402. Remove K Digits 移掉 K 位数字
https://leetcode.com/problems/remove-k-digits/description/
func removeKdigits(num string, k int) string {
digits := []byte(num)
n := len(digits)
stack := make([]byte, 0, n)
for _, digit := range digits {
for k > 0 && len(stack) > 0 && stack[len(stack)-1] > digit {
k--
stack = stack[:len(stack)-1]
}
stack = append(stack, digit)
}
for k > 0 && len(stack) > 0 {
k--
stack = stack[:len(stack)-1]
}
return toString(stack)
}
func toString(digits []byte) string {
for len(digits) > 0 && digits[0] == '0' {
digits = digits[1:]
}
if len(digits) == 0 {
return "0"
}
return string(digits)
}
LC 853. Car Fleet 车队
https://leetcode.com/problems/car-fleet/description/
func carFleet(target int, position []int, speed []int) int {
cars := make([][]int, len(position))
for i := range cars {
cars[i] = []int{position[i], speed[i]}
}
slices.SortFunc(cars, func(a, b []int) int {
return a[0] - b[0]
})
times := make([]float64, len(cars))
for i, car := range cars {
times[i] = float64(target-car[0]) / float64(car[1])
}
count := 0
maxTimes := 0.0
for i := len(times) - 1; i >= 0; i-- {
if times[i] > maxTimes {
count++
maxTimes = times[i]
}
}
return count
}