🥳前端算法基础之乱序数组找第K个数-每日一练

前言

今天的文章分享如何在乱序的数组中,找到第 K 大的数

之前的文章也分享了一篇关于找数组中最小的 k 个数的内容,还要求复杂度为 logn。那今天为什么还要介绍复杂度更高的算法呢。其实之前的算法复杂度低是建立在一个排序二叉树上面的。在排序二叉树上找任何的数据复杂度都是 logn。而今天的算法是建立在乱序的数组上。

在乱序的数组中,如何找到第 K 个数呢。要不要先排个序?将数组排好序了,获取下标为 k-1 的数,就是我们要找的数了。不过最快的排序算法的复杂度是 nlogn,不满足题目的要求

该怎么办呢?这里就需要用到之前介绍过的快速排序了

快速排序(Quick Sort)是一种常用的排序算法,其平均时间复杂度为 O(nlogn)。快速排序的主要思想是分治法,通过递归地将数组划分为较小和较大的两个子数组,然后递归地排序两个子数组。

快速排序的实现步骤如下:

  1. 选择一个基准元素(pivot),通常选择第一个或最后一个元素。
  2. 将数组划分为两个子数组,一个子数组中的元素都比基准元素小,另一个子数组中的元素都比基准元素大。
  3. 对这两个子数组递归地应用快速排序算法,直到子数组的大小为1或0,即它们已经有序。

具体算法分析,可以看这篇文章:

快序排序过程中,会使用一个基准元素,将数组划分成左右两个子数组,左边数组中的所有内容都会比基准元素小,右边数组都会比基准元素小。这时候,我们就看看左边数组的长度是否大于 K,如果是,那么第 K 个数肯定在左边的数组中,如果基准元素的下标刚好是 k-1,那么基准元素就是我们要找的,其他情况就是在右边数组里面了。

如果在左边数组里面,我们就在左边数组中再次选取一个基准元素重复上面的动作,直到找到我们要找的

数组下标从 0 开始。对于第 K 个元素,从 1 开始计数

下面看看代码如何实现:🥳每日一练-快速排序-JS简单版

代码实现

javascript 复制代码
// splitArray 函数用于将数组划分为两个子数组,其中一个子数组中的元素都小于基准元素,另一个子数组中的元素都大于基准元素
const splitArray = (array, left, right) => {
    // 选择数组的第一个元素作为基准元素
    const temp = array[left];

    // 使用双指针从右向左遍历数组,将小于基准元素的元素放到左边,大于基准元素的元素放到右边
    while (left < right) {
        while (left < right && array[right] > temp) right--;
        array[left] = array[right];
        while (left < right && array[left] <= temp) left++;
        array[right] = array[left];
    }

    // 将基准元素放到正确的位置
    array[left] = temp;

    // 返回基准元素的索引
    return left;
};

// findKNum 函数用于找到数组中第 k 个小的元素
const findKNum = (array, k, left, right) => {
    // 如果数组的长度为 0 或 1,直接返回对应的元素
    if (left > right) return null;

    // 使用 splitArray 函数将数组划分为两个子数组
    const mid = splitArray(array, left, right);

    // 计算左子数组的长度
    const leftLen = mid - left + 1;

    // 如果左子数组的长度等于 k,说明第 k 个元素就是基准元素
    if (leftLen == k) return array[mid];

    // 如果左子数组的长度大于 k,说明第 k 个元素在左子数组中,递归查找左子数组
    if (leftLen > k) return findKNum(array, k, left, mid - 1);

    // 如果左子数组的长度小于 k,说明第 k 个元素在右子数组中,递归查找右子数组
    return findKNum(array, k - leftLen, mid + 1, right);
};

findKNum 函数用于找到数组中第 k 个小的元素。其中就利用了快速排序的思想。先使用 splitArray 函数将数组划分为两个子数组,然后计算左子数组的长度,如果左子数组的长度等于 k,说明第 k 个元素就是基准元素;如果左子数组的长度大于 k,说明第 k 个元素在左子数组中,递归查找左子数组;如果左子数组的长度小于 k,说明第 k 个元素在右子数组中,递归查找右子数组。

需要注意的是,在右数组中递归查找的时候,需要将 k - leftLen,表示已经找过了前面 leftLen 个数,只要找剩下的第 k - leftLen 就可以了

这篇文章有对这种处理做了详细的解释,可以移步了解: 🥳每日一练-找到数组中最小的k个数-JS简易版

测试代码

javascript 复制代码
const array = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];

const k = findKNum(array, 5, 0, array.length - 1);
console.log(k); 
// 50

为了让测试结果更直观,这里将数组设置为有序。代码中想找到第 5 大的数,那么 k 就应该是 50. 如打印的那样

下面测测乱序

javascript 复制代码
const array = [12, 32, 36, 74, 5, 26, 17, 78, 49, 10];

console.log(findKNum(array, 1, 0, array.length - 1));
console.log(findKNum(array, 2, 0, array.length - 1));
console.log(findKNum(array, 3, 0, array.length - 1));
console.log(findKNum(array, 4, 0, array.length - 1));
console.log(findKNum(array, 5, 0, array.length - 1));

// 5
// 10
// 12
// 17
// 26

这里也为了测试结果更加直观,直接将前 5 个数字打印了出来😄

总结:

这篇文章分享了在乱序数组中找到第 k 个数,主要利用了快速排序的思想,和差分数组之后的长度信息利用,不算难。算是帮大家复习了下快速排序吧哈哈

有什么问题可以评论区留言哦。我每天都会分享一篇算法小练习,喜欢就点赞+关注吧

相关推荐
Jiaberrr8 分钟前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
我是哈哈hh41 分钟前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
Tisfy1 小时前
LeetCode 2187.完成旅途的最少时间:二分查找
算法·leetcode·二分查找·题解·二分
Mephisto.java1 小时前
【力扣 | SQL题 | 每日四题】力扣2082, 2084, 2072, 2112, 180
sql·算法·leetcode
robin_suli1 小时前
滑动窗口->dd爱框框
算法
丶Darling.1 小时前
LeetCode Hot100 | Day1 | 二叉树:二叉树的直径
数据结构·c++·学习·算法·leetcode·二叉树
labuladuo5201 小时前
Codeforces Round 977 (Div. 2) C2 Adjust The Presentation (Hard Version)(思维,set)
数据结构·c++·算法
安冬的码畜日常2 小时前
【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)
开发语言·前端·javascript·信息可视化·数据可视化·d3.js
jiyisuifeng19912 小时前
代码随想录训练营第54天|单调栈+双指针
数据结构·算法
太阳花ˉ2 小时前
html+css+js实现step进度条效果
javascript·css·html