算法题目整理01

本文整理了算法题目,重点讨论了如何利用堆排序解决如何快速获取日志文件中TOP N的搜索关键字问题。介绍了堆排序的原理,包括完全二叉树、大顶堆和小顶堆的概念,以及静态和动态数据集合情况下解决问题的方法。
摘要由CSDN通过智能技术生成

算法题目整理01

此处链接到—>算法题目整理02

之前关于算法准备的比较少,自己懂一些算法的基础知识,但是在LeetCode上做的题目也不多。

被问到算法,手写出来,对自己的难度还是很大滴~。

但知识都是死的,多花一些时间思考,总有一天能够学会的。

面试官问了两道算法题目,但自己平时做的少,再加上自己也没有多少面试经验。

其实这两道都不难,不过看的少,印象也少,回答的都不太好。


第一道题目。

假设我们现在有包含10亿个搜索关键字的日志文件,如何快速获取热门榜上的TOP N 的搜索关键字呢?

被问到时,脑子里有一些模糊的印象,忘了在哪本书中,还是哪个小课中学过,看过获得Top 10的最热的数据。

没有回答出来,最后面试官给了一个堆排序的一个思路,当时只想到一个(大顶堆)和(小顶堆)的概念,想起二叉树,其他Top N的问题,没理清楚逻辑~~

堆排序:

先来看一看关于堆排序(Heap Sort)的wiki 定义

Heapsort is a comparison-based sorting algorithm.

Heapsort can be thought of as an improved selection sort: like selection sort, heapsort divides its input into a sorted and an unsorted region, and it iteratively shrinks the unsorted region by extracting the largest element from it and inserting it into the sorted region.

Unlike selection sort, heapsort does not waste time with a linear-time scan of the unsorted region; rather, heap sort maintains the unsorted region in a heap data structure to more quickly find the largest element in each step.

The buildMaxHeap() operation is run once, and is O(n) in performance.

The siftDown() function is O(log n), and is called n times. Therefore, the performance of this algorithm is O(n + n log n) = O(n log n).

  • 堆是一个完全二叉树。
  • 堆的每一个节点的值都必须大于等于(或小于等于)其子树的每一个节点的值。
  • 堆排序的时间复杂度为O(n log n)

具体来看一下概念:

  • 完全二叉树: 除了最后一层,其他节点的个数都是满的,最后一层的节点向左排列。
  • 根大于等于子树每个节点的值,大顶堆
  • 根小于等于子树每个节点的值,小顶堆

可以在这个网址查看到堆排序的整个流程,点击(Heap Sort)查看整个过程。

visualization/HeapSort

堆排序的整个流程

  1. 建堆

如图所示: 给出一个无序的数组,把数组在原地建成一个堆。

索引第一个值 463, 放在根节点,之后 994和 14 分别放在根节点的左右节点。

依次向下排列,最后一层的节点向左排列,最后形成一颗 完全二叉树。

在这里插入图片描述

  1. 堆化

    即把这个堆按照一定的排序方式(此处使用大顶堆的方式)。

    从右下的元素(完全二叉树结束的地方),开始比较子节点和其父节点的值,开始替换和排序,此处应交换414 和988, 将988(大值)作为其根节点。

    之后从下到上一层层的开始堆化,同时,上层堆化的结果也会影响下层的重新堆化(查新排序)。

在这里插入图片描述

**

最后堆化的结果

此处可以看到: 整个数组中最大元素994次,已经排序到根节点的位置。

在这里插入图片描述

整个建堆+ 堆化的时间复杂度为O(n)的时间复杂度。

  1. 排序

    建堆 --> 堆化之后,数组中的数据已经是按照大顶堆的特性来进行排序的。

    数组的根节点,也就是整个数组中最大的元素。将其与最后一个元素交换(index = 30),最大元素放到了最后的位置,数组尾部。

    之后重新堆化,将剩下的(n-1)个元素,重新构建成堆,放到下标n-1 的位置。依次排放——>

在这里插入图片描述

在这里插入图片描述

​ 最后的结果: 得到一个排序完整的数组

在这里插入图片描述


整体下来,建堆+堆化 过程的时间复杂度为O(n),排序过程的时间复杂度为O(n log n )。所以,堆排序的整体时间复杂度为:O(n log n )


回到开头的问题:如何在10亿个关键字搜索关键字的日志文件( log ) 中获得Top N的关键字呢?

我们把问题分成两类,针对静态数据集合(不会 变)和针对 动态数据集合(集合数据不确定,数据会动态的插入)

  • 静态数据

    维护一个大小为 N 的小顶堆(左右节点大于根节点), 之后遍历这个日志文件的数组,取出元素与堆顶元素比较。

    • 小于根节点,直接删除,不做处理
    • 大于根节点,删除根节点,插入元素,重新堆化(复合小顶堆的特性)。

    遍历数组O(n)的时间复杂度,堆化需要O(log N)的时间复杂度(N为前N 个元素的个数)。最坏情况下,时间复杂度为:O(n logN)的时间复杂度。

  • 动态数据

    实时的Top N 个元素,分为两个步骤:(添加数据) 和(询问当前N大数据)。

    我们可以一直维护一个N 大小的小顶堆,不断的插入元素

    • 小于根节点,直接删除,不做处理
    • 大于根节点,删除根节点,插入元素,重新堆化(复合小顶堆的特性)。

在这里插入图片描述

这样,无论何时查询前K大元素,我们都可以实时的返回出去啦。

推荐阅读:

58沈剑:拜托,面试别再问我TopK了!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值