前端算法之堆--桶排序和快速排序

2024-01-06 22:36

本文主要是介绍前端算法之堆--桶排序和快速排序,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  • 前 K 个高频元素
    • 使用API实现
    • 使用桶排序
  • 数组中的第K个最大元素
    • 直接使用 javaScript API
    • 使用快速排序
  • 扩展:桶排序
    • 例子
  • 扩展:快速排序
    • 快速排序的步骤:
    • 快速排序示例:

前 K 个高频元素

leetcode链接:https://leetcode.cn/problems/top-k-frequent-elements/

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:

输入: nums = [1], k = 1
输出: [1]

提示:

1 <= nums.length <= 105
k 的取值范围是 [1, 数组中不相同的元素的个数]
题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

进阶: 你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。

更多详细内容,请微信搜索“前端爱好者戳我 查看

使用API实现

/*** @param {number[]} nums* @param {number} k* @return {number[]}*/
var topKFrequent = function(nums, k) {let map = new Map() // 定义一个map类型let arr = [...new Set(nums)] // 获取数组去重后的元素// 一次遍历nums值,把他们出现的频次放在map里面nums.map(num => {if(map.has(num)){map.set(num,map.get(num) + 1)} else {map.set(num,1)}})// 现针对去重元素进行排序return arr.sort((a,b) => {map.get(b) - map.get(a)}).slice(0,k)
};

使用桶排序

桶排序适用 top k中 频次题,计数排序适用 top k中 值的题

/*** @param {number[]} nums* @param {number} k* @return {number[]}*/// 桶排序 原理:1. 将数据滑倒到有限个桶里面,再将桶进行排序
// 用map存储频次,用数组表达桶,频次作为数据下表表达,针对不同的频次的熟悉,聚合
var topKFrequent = function(nums, k) {let map = new Map() // 定义一个map类型 // 一次遍历nums值,把他们出现的频次放在map里面nums.map(num => {if(map.has(num)){map.set(num,map.get(num) + 1)} else {map.set(num,1)}})if(map.size <=k ){return [...map.keys()]}return bucketSort(map,k)
};// 桶排序内容
const bucketSort = (map,k) => {let arr = [] let res = [] //结果// 针对map中每个元素遍历map.forEach((value,key) => {// 可以利用频次作为下标,降数据分配到桶里if(!arr[value]) {arr[value] = [key]} else {arr[value].push(key)} })// 倒序排列for(let i = arr.length -1 ; i >=0 && res.length < k ;i-- ){if(arr[i]){res.push(...arr[i]) }}return res
}

数组中的第K个最大元素

leetcode地址:https://leetcode.cn/problems/kth-largest-element-in-an-array/

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

输入: [3,2,1,5,6,4], k = 2
输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4

提示:

1 <= k <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4

直接使用 javaScript API

/*** @param {number[]} nums* @param {number} k* @return {number}*/
var findKthLargest = function(nums, k) {nums.sort((a,b) => b-a ).slice(0,k)return nums[k -1]
};

使用快速排序

快速排序:本质是:拆分,分而治之

/*** @param {number[]} nums* @param {number} k* @return {number}*/
var findKthLargest = function(nums, k) {// 快速排序 分而治之// 1. 找到基准值// 1. 比他大的房右边,小的放左边// 3. 按照1 2 步骤继续拆分,直到找到下标// 创建指针,左右两端// 1. 左侧index 大于 右侧指针indexquickSort(nums)return nums[nums.length - k]
};// 快排
let quickSort = (arr) => {quick(arr,0,arr.length -1) // 基准:数组,起始值(开始指针),终止值(结束指针)
}const quick = (arr, left,right)=>{let index;if(left < right){index = partition(arr, left,right)// 左侧小于基准值if(left < index - 1){quick(arr,left,index - 1 )}if(index < right){quick(arr,index,right)}}
}// 找基准值
const partition = (arr, left,right)=>{let datum = arr[Math.floor(Math.random() * (right - left + 1)) + left] // 基准值let i = left // 左侧let j = right // 右侧while ( i <= j){ // 左侧while(arr[i] < datum){i ++ }// 右侧while(arr[j] > datum){j --}if( i <= j ){[arr[i],arr[j]] = [arr[j],arr[i]]  // 注意这里i+=1j-=1}}return i
}

扩展:桶排序

桶排序(Bucket Sort)是一种基于分治思想的排序算法。

它的基本思想是将要排序的数据分到几个有序的桶中,每个桶里的数据再单独进行排序。通常情况下,桶的数量是根据数据的分布情况来决定的。

桶排序的过程可以描述如下:

  1. 找出待排序数列中的最大值和最小值。
  2. 设置若干个桶,并将数据按照一定的规则放入对应的桶中。
  3. 对于每个非空桶,对其中的数进行排序。
  4. 将所有桶中的数据依次取出,组成有序数列。

桶排序的时间复杂度为O(n),但需要额外的空间来存储桶。在数据分布均匀的情况下,桶排序的效率很高,但如果数据分布不均匀,则可能会导致某些桶的大小远远超过其他桶,从而导致效率降低。

桶排序适用于数据范围不大的情况下,且数据分布均匀的情况下效率最高。在实际应用中,桶排序通常被用于外部排序,即当待排序数据无法全部载入内存时,先将数据分割成若干个能够装入内存的部分,对每部分进行排序,最后再将它们合并起来。

例子

下面举一个例子来说明桶排序的过程:

假设有一个待排序的数组[3, 6, 1, 8, 2, 5, 7, 4],现在我们要使用桶排序对其进行排序,具体步骤如下:

  1. 找出待排序数列中的最大值和最小值:最大值为8,最小值为1。
  2. 设置若干个桶,并将数据按照一定的规则放入对应的桶中。这里我们可以设置8个桶,每个桶的范围为[min + i * (max - min) / n, min + (i + 1) * (max - min) / n),其中n为桶的数量,i为桶的编号,min和max分别为待排序数列的最小值和最大值。按照这个规则,可以将待排序数组分到各个桶中,得到如下内容:
  • 桶1: [1, 2]
  • 桶2: [3, 4]
  • 桶3: [5]
  • 桶4: [6, 7]
  • 桶5: [8]
  1. 对于每个非空桶,对其中的数进行排序。这里可以使用插入排序等简单的排序算法对桶中的数据进行排序,得到如下内容:
  • 桶1: [1, 2] -> [1, 2]
  • 桶2: [3, 4] -> [3, 4]
  • 桶3: [5] -> [5]
  • 桶4: [6, 7] -> [6, 7]
  • 桶5: [8] -> [8]
  1. 将所有桶中的数据依次取出,组成有序数列。这里可以先将各个桶中的数据合并起来,得到一个有序的数组,即[1, 2, 3, 4, 5, 6, 7, 8]。

因此,桶排序的时间复杂度为O(n),但需要额外的空间来存储桶。在数据分布均匀的情况下,桶排序的效率很高,但如果数据分布不均匀,则可能会导致某些桶的大小远远超过其他桶,从而导致效率降低。

扩展:快速排序

快速排序(Quick Sort)是一种常用的排序算法,它通过将一个数组分割成两个子数组来进行排序。具体而言,快速排序选择一个基准元素(pivot),将数组中小于基准元素的元素放在基准元素的左边,大于基准元素的元素放在基准元素的右边,然后递归地对左右两个子数组进行排序。

快速排序的步骤:

  1. 选择基准元素(pivot),通常可以选择第一个元素、最后一个元素或者随机选择一个元素作为基准。
  2. 将数组划分为两个子数组:一个子数组中的元素都小于等于基准元素,另一个子数组中的元素都大于基准元素。这个过程称为分区(partition),可以使用双指针法实现。
  3. 对两个子数组分别进行递归排序,即重复步骤1和步骤2。
  4. 递归的基本情况是子数组的长度为0或1,此时可以认为子数组已经有序。
  5. 合并所有子数组的结果,得到最终的排序结果。

快速排序示例:

假设有一个待排序的数组[8, 4, 2, 9, 3, 5, 1, 6, 7],我们使用快速排序对其进行排序,具体步骤如下:

  1. 选择基准元素,可以选择第一个元素8。
  2. 使用双指针法将数组分为两个子数组:小于等于8的放在左边,大于8的放在右边。经过一次分区后,数组变为[4, 2, 3, 5, 1, 6, 7, 8, 9],此时基准元素8已经位于正确的位置。
  3. 对左侧子数组[4, 2, 3, 5, 1, 6, 7]和右侧子数组[9]分别进行递归排序。
  4. 对左侧子数组进行快速排序,选择基准元素4。经过一次分区后,左侧子数组变为[1, 2, 3, 4, 5, 6, 7],基准元素4位于正确位置。
  5. 对右侧子数组[9]进行递归排序,由于长度为1,无需处理。
  6. 合并左右子数组的结果,得到最终的排序结果:[1, 2, 3, 4, 5, 6, 7, 8, 9]。

快速排序的平均时间复杂度为O(nlogn),最坏情况下(当选择的基准元素总是数组中的最大或最小元素)的时间复杂度为O(n^2)。但由于其实现简单、性能优秀,在实际应用中被广泛使用。

这篇关于前端算法之堆--桶排序和快速排序的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/577844

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

电脑桌面文件删除了怎么找回来?别急,快速恢复攻略在此

在日常使用电脑的过程中,我们经常会遇到这样的情况:一不小心,桌面上的某个重要文件被删除了。这时,大多数人可能会感到惊慌失措,不知所措。 其实,不必过于担心,因为有很多方法可以帮助我们找回被删除的桌面文件。下面,就让我们一起来了解一下这些恢复桌面文件的方法吧。 一、使用撤销操作 如果我们刚刚删除了桌面上的文件,并且还没有进行其他操作,那么可以尝试使用撤销操作来恢复文件。在键盘上同时按下“C

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig