Week 16 @ 2025 算法周记【队列 + 单调栈】
队列
LC 641. Design Circular Deque 设计循环双端队列
https://leetcode.com/problems/design-circular-deque/description/
type MyCircularDeque struct {
capacity int
size int
arr []int
rear int
}
func Constructor(k int) MyCircularDeque {
return MyCircularDeque {
capacity: k,
arr: make([]int, k),
rear: -1,
}
}
func (this *MyCircularDeque) InsertFront(value int) bool {
if this.IsFull() {
return false
}
if this.IsEmpty() {
this.onlyOne(value)
return true
}
newFront := this.index(this.frontIndex() + 1)
this.arr[newFront] = value
this.size++
return true
}
func (this *MyCircularDeque) onlyOne(value int) {
this.arr[0] = value
this.rear = 0
this.size = 1
}
func (this *MyCircularDeque) index(i int) int {
if i < 0 {
return i + this.capacity
}
if i >= this.capacity {
return i - this.capacity
}
return i
}
func (this *MyCircularDeque) InsertLast(value int) bool {
if this.IsFull() {
return false
}
if this.IsEmpty() {
this.onlyOne(value)
return true
}
newRear := this.index(this.rear - 1)
this.arr[newRear] = value
this.rear = newRear
this.size++
return true
}
func (this *MyCircularDeque) frontIndex() int {
return this.index(this.rear + this.size - 1)
}
func (this *MyCircularDeque) DeleteFront() bool {
if this.IsEmpty() {
return false
}
this.size--
return true
}
func (this *MyCircularDeque) DeleteLast() bool {
if this.IsEmpty() {
return false
}
this.rear = this.index(this.rear + 1)
this.size--
return true
}
func (this *MyCircularDeque) GetFront() int {
if this.IsEmpty() {
return -1
}
return this.arr[this.frontIndex()]
}
func (this *MyCircularDeque) GetRear() int {
if this.IsEmpty() {
return -1
}
return this.arr[this.rear]
}
func (this *MyCircularDeque) IsEmpty() bool {
return this.size == 0
}
func (this *MyCircularDeque) IsFull() bool {
return this.size == this.capacity
}
/**
* Your MyCircularDeque object will be instantiated and called as such:
* obj := Constructor(k);
* param_1 := obj.InsertFront(value);
* param_2 := obj.InsertLast(value);
* param_3 := obj.DeleteFront();
* param_4 := obj.DeleteLast();
* param_5 := obj.GetFront();
* param_6 := obj.GetRear();
* param_7 := obj.IsEmpty();
* param_8 := obj.IsFull();
*/
LC 1670. Design Front Middle Back Queue 设计前中后队列
https://leetcode.com/problems/design-front-middle-back-queue/description/
type FrontMiddleBackQueue struct {
left *list.List
right *list.List
}
func Constructor() FrontMiddleBackQueue {
return FrontMiddleBackQueue {
left: list.New(),
right: list.New(),
}
}
// 始终维护「尽可能平衡」&「奇数时左边少右边多」
func (this *FrontMiddleBackQueue) balance() {
// 维持「右边的数量 >= 左边的数量」
for this.right.Len() < this.left.Len() {
leftBack := this.left.Back()
this.right.PushFront(leftBack.Value)
this.left.Remove(leftBack)
}
// 位置「右边的数量 <= 左边的数量 + 1」
for this.right.Len() > this.left.Len() + 1 {
rightFront := this.right.Front()
this.left.PushBack(rightFront.Value)
this.right.Remove(rightFront)
}
}
func (this *FrontMiddleBackQueue) PushFront(val int) {
this.left.PushFront(val)
this.balance()
}
func (this *FrontMiddleBackQueue) PushMiddle(val int) {
this.left.PushBack(val)
this.balance()
}
func (this *FrontMiddleBackQueue) PushBack(val int) {
this.right.PushBack(val)
this.balance()
}
func (this *FrontMiddleBackQueue) PopFront() int {
if this.left.Len() != 0 {
front := this.left.Front()
this.left.Remove(front)
this.balance()
return front.Value.(int)
}
if this.right.Len() != 0 {
front := this.right.Front()
this.right.Remove(front)
this.balance()
return front.Value.(int)
}
return -1
}
func (this *FrontMiddleBackQueue) PopMiddle() int {
if this.right.Len() == 0 {
return -1
}
if this.left.Len() < this.right.Len() {
middle := this.right.Front()
this.right.Remove(middle)
this.balance()
return middle.Value.(int)
} else {
middle := this.left.Back()
this.left.Remove(middle)
this.balance()
return middle.Value.(int)
}
}
func (this *FrontMiddleBackQueue) PopBack() int {
if this.right.Len() == 0 {
return -1
}
back := this.right.Back()
this.right.Remove(back)
this.balance()
return back.Value.(int)
return -1
}
/**
* Your FrontMiddleBackQueue object will be instantiated and called as such:
* obj := Constructor();
* obj.PushFront(val);
* obj.PushMiddle(val);
* obj.PushBack(val);
* param_4 := obj.PopFront();
* param_5 := obj.PopMiddle();
* param_6 := obj.PopBack();
*/
LC 2073. Time Needed to Buy Tickets买票需要的时间
https://leetcode.com/problems/time-needed-to-buy-tickets/description/
func timeRequiredToBuy(tickets []int, k int) int {
// [0 ... i-1] [i] [i+1 ...]
// <tx> <tx-1>
total := 0
tx := tickets[k]
for i := 0; i <= k; i++ {
total += min(tickets[i], tx)
}
for i := k+1; i < len(tickets); i++ {
total += min(tickets[i], tx - 1)
}
return total
}
单调栈
模板:Calculate Next Greater Element
func calculateNextGreaterElement(nums []int) []int {
result := make([]int, len(nums))
ms := make([]int, 0, len(nums))
for i := len(nums) - 1; i >= 0; i-- {
for len(ms) > 0 && ms[len(ms)-1] <= nums[i] {
ms = ms[:len(ms)-1]
}
if len(ms) == 0 {
result[i] = -1
} else {
result[i] = ms[len(ms) - 1]
}
ms = append(ms, nums[i])
}
return result
}
LC 496. Next Greater Element I 下一个更大元素 I
https://leetcode.com/problems/next-greater-element-i/description/
func nextGreaterElement(nums1 []int, nums2 []int) []int {
nums2Map := make(map[int]int, len(nums2))
for i, v := range nums2 {
nums2Map[v] = i
}
next := calculateNextGreaterElement(nums2)
result := make([]int, len(nums1))
for i, v := range nums1 {
result[i] = next[nums2Map[v]]
}
return result
}
func calculateNextGreaterElement(nums []int) []int {
result := make([]int, len(nums))
ms := make([]int, 0, len(nums))
for i := len(nums) - 1; i >= 0; i-- {
// 5 3 2 1
for len(ms) > 0 && ms[len(ms)-1] <= nums[i] {
ms = ms[:len(ms)-1]
}
if len(ms) == 0 {
result[i] = -1
} else {
result[i] = ms[len(ms) - 1]
}
ms = append(ms, nums[i])
}
return result
}
LC 739. Daily Temperatures 每日温度
https://leetcode.com/problems/daily-temperatures/description/
func dailyTemperatures(temperatures []int) []int {
result := make([]int, len(temperatures))
ms := make([][]int, 0, len(temperatures))
for i := len(temperatures) - 1; i >= 0; i-- {
for len(ms) > 0 && ms[len(ms)-1][0] <= temperatures[i] {
ms = ms[:len(ms)-1]
}
if len(ms) > 0 {
d := ms[len(ms)-1][1]
result[i] = d - i
}
ms = append(ms, []int{temperatures[i], i})
}
return result
}
LC 503. Next Greater Element II 下一个更大元素 II
https://leetcode.com/problems/next-greater-element-ii/description/
func nextGreaterElements(nums []int) []int {
dupNums := append(nums, nums...)
dupNext := calculateNextGreaterElement(dupNums)
return dupNext[:len(nums)]
}
func calculateNextGreaterElement(nums []int) []int {
result := make([]int, len(nums))
ms := make([]int, 0, len(nums))
for i := len(nums) - 1; i >= 0; i-- {
// 5 3 2 1
for len(ms) > 0 && ms[len(ms)-1] <= nums[i] {
ms = ms[:len(ms)-1]
}
if len(ms) == 0 {
result[i] = -1
} else {
result[i] = ms[len(ms) - 1]
}
ms = append(ms, nums[i])
}
return result
}
不实际构造翻倍数组
func nextGreaterElements(nums []int) []int {
n := len(nums)
result := make([]int, n)
ms := make([]int, 0, n)
for i := 2 * n - 1; i >= 0; i-- {
ii := i % n
for len(ms) > 0 && ms[len(ms)-1] <= nums[ii] {
ms = ms[:len(ms)-1]
}
if len(ms) == 0 {
result[ii] = -1
} else {
result[ii] = ms[len(ms) - 1]
}
ms = append(ms, nums[ii])
}
return result
}
, multiple selections available,