一、队列
队列是一种先进先出的线性表。
它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
如图所示:
二、堆排序
1、概念:
- 堆栈是计算机的两种最基本的数据结构。堆的特点就是FIFO(first in first out)先进先出,可以理解成树的结构。堆在接收数据的时候先接收的数据会被先弹出。
- 栈的特性正好与堆相反,是属于FILO(first in/last out)先进后出的类型。栈处于一级缓存而堆处于二级缓存中。
2、堆节点的访问
通常堆是通过一维数组来实现的。在阵列起始位置为0的情况中
- 父节点i的左子节点在位置(2*i+1)
- 父节点i的右子节点在位置(2*i+2)
- 子节点i的父节点在位置floor((i-1)/2)
3、堆操作
- 最大堆调整(MAX_Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点。这是核心步骤,在建堆和堆排序都会用到。比较i的根节点和与其所对应i的孩子节点的值。当i根节点的值比左孩子节点的值要小的时候,就把i根节点和左孩子节点所对应的值交换,当i根节点的值比右孩子的节点所对应的值要小的时候,就把i根节点和右孩子节点所对应的值交换。然后再调用堆调整这个过程,可见这是一个递归的过程。
- 建立最大堆(Build_Max_Heap):将堆所有数据重新排序。建堆的过程其实就是不断做最大堆调整的过程,从len/2出开始调整,一直比到第一个节点。
- 堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算。堆排序是利用建堆和堆调整来进行的。首先先建堆,然后将堆的根节点选出与最后一个节点进行交换,然后将前面len-1个节点继续做堆调整的过程。直到将所有的节点取出,对于n个数我们只需要做n-1次操作。
三、编程练习
第一题(239)
内容描述:
- 最大堆调整(MAX_Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点。这是核心步骤,在建堆和堆排序都会用到。比较i的根节点和与其所对应i的孩子节点的值。当i根节点的值比左孩子节点的值要小的时候,就把i根节点和左孩子节点所对应的值交换,当i根节点的值比右孩子的节点所对应的值要小的时候,就把i根节点和右孩子节点所对应的值交换。然后再调用堆调整这个过程,可见这是一个递归的过程。
- 建立最大堆(Build_Max_Heap):将堆所有数据重新排序。建堆的过程其实就是不断做最大堆调整的过程,从len/2出开始调整,一直比到第一个节点。
- 堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算。堆排序是利用建堆和堆调整来进行的。首先先建堆,然后将堆的根节点选出与最后一个节点进行交换,然后将前面len-1个节点继续做堆调整的过程。直到将所有的节点取出,对于n个数我们只需要做n-1次操作。
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口 k 内的数字。滑动窗口每次只向右移动一位。
返回滑动窗口最大值。
示例:
输入: nums =[1,3,-1,-3,5,3,6,7]
, 和 k = 3 输出:[3,3,5,5,6,7] 解释:
滑动窗口的位置 最大值 --------------- ----- [1 3 -1] -3 5 3 6 7 3 1 [3 -1 -3] 5 3 6 7 3 1 3 [-1 -3 5] 3 6 7 5 1 3 -1 [-3 5 3] 6 7 5 1 3 -1 -3 [5 3 6] 7 6 1 3 -1 -3 5 [3 6 7] 7
注意:
你可以假设 k 总是有效的,1 ≤ k ≤ 输入数组的大小,且输入数组不为空。
进阶:
你能在线性时间复杂度内解决此题吗?
解题方案:
- 思路:窗口的滑动过程中数字的进出类似一个队列中元素的出队入队,采用一个队列queue存储可能成为最大值的元素下标。如果每次入队的新元素比队尾元素小,则将其删除,直至队尾元素大于新元素或队空。(因为被删除元素既没有当前元素大,也没有当前元素新,所以肯定不会替代当前元素成为最大值的)
找最大值时从队头开始,如果队头元素对应的index不在当前窗口则将其删除,直到找到在窗口中的元素,即为最大值。 - 代码:
class Solution(object): def maxSlidingWindow(self, nums, k): """ :type nums: List[int] :type k: int :rtype: List[int] """ if not nums: return [] from collections import deque dq = deque() n = len(nums) ans = [] for i in range(k-1): while len(dq) > 0: if nums[dq[-1]] <= nums[i]: dq.pop() else: break dq.append(i) for i in range(k-1, n): while len(dq) > 0: if nums[dq[-1]] <= nums[i]: dq.pop() else: break dq.append(i) while dq[0] < i-k+1: dq.popleft() ans.append(nums[dq[0]]) return ans
- 运行结果:
四、回顾往期
【任务一】
数组:学习哈希表思想,并完成leetcode上的两数之和(1)及Happy Number(202)!(要求全部用哈希 思想实现!)https://shimo.im/sheet/xjO2SX8fJJkRTJ4s/ 《DW编程集训第二期-任务1》,可复制链接 后用石墨文档 App 打开
【任务二】
链表:学习单链表知识,实践环形链表(142,要求至少两种方法!)及反转一个单链表(206),不限制语 言!https://shimo.im/sheet/1wghoDz457oLIOqh/ 《DW编程集训第二期-任务2》,可复制链接后用石墨 文档 App 打开