🥳前端算法基础之乱序数组找第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 个数,主要利用了快速排序的思想,和差分数组之后的长度信息利用,不算难。算是帮大家复习了下快速排序吧哈哈

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

相关推荐
Martin -Tang1 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
passer__jw7671 小时前
【LeetCode】【算法】3. 无重复字符的最长子串
算法·leetcode
passer__jw7671 小时前
【LeetCode】【算法】21. 合并两个有序链表
算法·leetcode·链表
sweetheart7-71 小时前
LeetCode22. 括号生成(2024冬季每日一题 2)
算法·深度优先·力扣·dfs·左右括号匹配
SRY122404192 小时前
javaSE面试题
java·开发语言·面试
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
景鹤4 小时前
【算法】递归+回溯+剪枝:78.子集
算法·机器学习·剪枝
_OLi_4 小时前
力扣 LeetCode 704. 二分查找(Day1:数组)
算法·leetcode·职场和发展