代码随想录 day13 第五章 栈与队列part03

今日内容:

●  239. 滑动窗口最大值

●  347.前 K 个高频元素

●  总结

1. 滑动窗口最大值 (一刷至少需要理解思路)

关联 leetcode 239. 滑动窗口最大值

  • 思路
    • 使用单调队列来实现
      • 单调队列:
        • 整个队列元素 单调递减/递增
      1. 保证队列里的元素 从大到小 排列
        1. 不需要对窗口内的数进行排序
        2. 保证进入窗口内,后面的数小于前面的数即可
  • 题解
    • 自己实现一个单调队列

      1. pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
      2. push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止
      3. front(): 返回需要的最大值
    • 代码实现

      // MyQueue 自定义的单调队列
      // Back 进 Front 出
      type MyQueue struct {
      	queue []int
      }
      
      func NewMyQueue() *MyQueue {
      	return &MyQueue{queue: make([]int, 0)}
      }
      
      func (q *MyQueue) Empty() bool {
      	return len(q.queue) == 0
      }
      
      func (q *MyQueue) Pop(x int) {
      // 只 pop() 队首元素的原因:
      // 其他元素在push()的时候已经被清洗掉了
      	if !q.Empty() && x == q.Front() {
      		//这里可以不用做判空
      		//if len(q.queue) > 1 {
      		//	q.queue = q.queue[1:]
      		//} else {
      		//	q.queue = make([]int, 0)
      		//}
      		q.queue = q.queue[1:]
      	}
      
      }
      
      // Push
      // 入队
      // 如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
      // 这样就保持了队列里的数值是单调从大到小的了。
      func (q *MyQueue) Push(x int) {
      	for !q.Empty() && x > q.Back() {
      		// 将要入队的元素比队尾元素还大 
      		q.queue = q.queue[:len(q.queue)-1] // 移除队尾元素
      	}
      	q.queue = append(q.queue, x)
      }
      
      func (q *MyQueue) Front() int {
      	return q.queue[0]
      }
      
      func (q *MyQueue) Back() int {
      	return q.queue[len(q.queue)-1]
      }
      
      func maxSlidingWindow(nums []int, k int) []int {
      	res := make([]int, 0)
      	myQueue := NewMyQueue()
      	for i := 0; i < k; i++ {
      		myQueue.Push(nums[i])//将前 k个 元素放入队列中
      	}
      	res = append(res, myQueue.Front())
      	for i := k; i < len(nums); i++ {
      		myQueue.Pop(nums[i-k])//真正开始移除元素,移除的是 nums 里面的元素,按值移除元素,从 nums[0]开始移除
      		myQueue.Push(nums[i])//加入新元素
      		res = append(res, myQueue.Front())
      	}
      	return res
      }
      
      

2. 前 K 个高频元素  (一刷至少需要理解思路)

关联 347.前 K 个高频元素

  • 现有哈希表【Map】统计元素出现次数
  • 使用小顶堆【优先队列】来实现排序
    • 小顶堆,每次弹出来是最小的那个元素
  • 思路
    • 解法1: 自己构建小顶堆, 时间复杂度 O(n*logk)
    • 解法2: 对统计好的Map做排序, 时间复杂度 O(n*logn)

3. 总结

  • 面试题:栈里面的元素在内存中是连续分布的么?
    • 依赖实现栈的底层容器
  • 栈实现队列:
    • 需要两个栈;出栈+入栈
  • 队列实现栈
    • 最少需要一个队列:循环队列即可
  • 编译器在词法分析中处理括号匹配逻辑,就使用了栈的数据结构
  • 递归的实现也是依赖栈
    • 函数栈,函数独享的内存空间,实现了函数彼此调用

9. 题外话

  • 优先级队列
    • 披着队列外衣的栈
    • 对外接口
      • 从对头取元素
      • 从队尾添加元素
    • 内部依照元素的权重排列
  • 快速排序
    • 一棵完全二叉树,树中每个节点的值都不小于(大于)其左右孩子的值
    • 如果对满二叉树的结点进行编号, 约定编号从根结点起, 自上而下, 自左而右。则深度为k的, 有n个结点的二叉树, 当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时, 称之为完全二叉树

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值