Skip to content

Latest commit

 

History

History

topic11_heap

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

堆题目 总结

介绍

时间:2020/4/12 Topic : 堆题目 复杂度格式: 时间复杂度, 空间复杂度

题目介绍

933. 最近的请求次数

  1. 方法:队列直接应用

堆排序

基本介绍

  1. 大顶堆:每个结点的值都大于或等于其左右孩子结点的值;
  2. 小顶堆:每个结点的值都小于或等于其左右孩子结点的值;

基本思路

1.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;

2.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;

3.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

复杂度

  • 时间复杂度:O(n+nlogn)
  • 空间复杂度:O(1)

参考

  1. 堆排序介绍

215. 数组中的第K个最大元素

方法一:数组法

基本介绍
  1. 考虑到 需要找到 第 k 大 的 数,所以可以将前 k 大 的数 都保存到 一个 数组中
思路
  1. 定义 一个 长度为 k+1 的数组 res_list,用于保存前 k+1 个 数;
  2. 遍历数组,然后比较当前元素 num 和 res_list 中 元素 间的大小(从后到前比较):
    1. 若 大于,则将 res_list 后移,然后插入 num
复杂度

时间复杂度:$O(n*(k+1))$

空间复杂度:$O(k+1)$

方法二:堆排序法

基本介绍
  1. 利用堆 每一次 都能 找到 当前 最大的数,所以只要 进行 k 次 堆排序 即可找到 第 k 大 的数
思路
  1. 编写堆排序算法;
  2. 进行 k 次 堆排序;
复杂度

时间复杂度:$O(n*nlogK)$

空间复杂度:$O(1)$

方法三:快排法

思路
  1. 对 数组进行快排,然后 取位置 k 元素 即可;
复杂度

时间复杂度:$O(nlogn)$

空间复杂度:$O(1)$

方法一的延伸:用一个最小堆存前k个最大的数

378. 有序矩阵中的第K小的元素

方法一 暴力的最小堆/优先队列

思路
  1. 建立大小为k的最大堆,时间O(k);
    1. 遍历每一个元素,如果比堆顶小则加入堆,最后返回堆顶元素即为第k小元素。时间O(n^2logk);
复杂度

时间复杂度:O( k + n^2logk)

空间复杂度O(k)

方法二 转化为 一维数组

思路
  1. 首先将二维数组合并成对应的一维数组
  2. 然后对这个一维数组排序,今天我使用的快速排序
  3. 最后返回第k-1个元素即可
复杂度

时间复杂度:$O(n^2logn)$

空间复杂度:$O(n^2)$

方法三 二分查找

思路
  1. 找出二维矩阵中最小的数left,最大的数right,那么第k小的数必定在left~right之间
  2. mid=(left+right) / 2;在二维矩阵中寻找小于等于mid的元素个数count
  3. 若这个count小于k,表明第k小的数在右半部分且不包含mid,即left=mid+1, right=right,又保证了第k小的数在left~right之间
  4. 若这个count大于k,表明第k小的数在左半部分且可能包含mid,即left=left, right=mid,又保证了第k小的数在left~right之间
  5. 因为每次循环中都保证了第k小的数在left~right之间,当left==right时,第k小的数即被找出,等于right
复杂度

时间复杂度:$O(n^2logn)$

空间复杂度:$O(n^2)$

方法四 堆排序

思路
  1. 因为每一行都是有序的,所以每一行的最小值(最左边)中最小一个必定是矩阵的最小值。。
  2. 取出这个最小值(即整个矩阵的最小值),同时使用这一行的下一个元素参与下一次比较。
  3. 循环上述步骤直到取到第k个最小值。
复杂度

时间复杂度:$O(min(k,N)) + k*O(log(min(k,N)))$

空间复杂度:$O(min(k,N))$

295. 数据流的中位数

方法一 两个堆

思路
  1. 建立一个大顶堆(小的那一半)一个小顶堆(大的那一半元素),堆顶保存着数组的中间两个数。
  2. 插入的时候:
    1. 若两个堆长度一样,则插入新元素,会先加到大顶堆,再把大堆顶元素加到小顶堆;
    2. 若第一个堆长度大于第二个,则插入新元素,会先加到小顶堆,再把小堆顶元素加到大顶堆;
  3. 查询时:
    1. 若两个堆长度一样, 取两个堆顶平均;
    2. 若第一个堆长度大于第二个,小顶堆堆顶元素
复杂度

时间复杂度:O(logn)

空间复杂度:$O(n)$

方法二

思路

一种针对本体比较合适而且简单的解法,使用二分插入,python自带的bisect,初始化一个数组,当数组为空时直接append,如果不为空,则使用bisect.insort_left,按顺序插入元素,这样每一步过后数组都是有序的,每一步加入元素只是需要二分查找插入位置

复杂度

时间复杂度O(lgn) + O(n)

空间复杂度O(n)