【 每天学习一点算法 2026/03/23】数组中的第K个最大元素

每天学习一点算法 2026/03/23

题目:数组中的第K个最大元素

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

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

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

  1. 最简单的方法就是先排序然后取第 k - 1 个元素

    typescript 复制代码
    function findKthLargest(nums: number[], k: number): number {
      return nums.sort((a, b) => b - a)[k - 1]
    };
  2. 上面的方法取决于排序算法的时间复杂度肯定不是我们想要的,我们可以利用快速排序方法来解决这个问题

    快速排序的关键在于选取一个基准值,然后将 大于 和 小于 基准值数放在两个数组中,然后在递归传递这两个数组,继续选取基准值分割,直到完成排序。

    • 假如 基准值 左边元素个数小于 k - 1,那么需要在右边的数组中寻找新的基准值
    • 假如 基准值 左边元素个数大于 k - 1,那么需要在左边的数组中寻找新的基准值
    • 假如 基准值 左边刚好有 k - 1 元素,那么这个基准值就是第 k 大的元素
    typescript 复制代码
    function findKthLargest(nums: number[], k: number): number {
      if (nums.length === 1) return nums[0]; // 只有一项直接返回
      const base = nums[Math.floor(Math.random() * nums.length)]; // 随机基准值
      const left: number[] = []
      const right: number[] = []
      const equal: number[] = []
      // 利用基准值分割数组
      for (const item of nums) {
        if (item < base) {
          right.push(item)
        } else if (item > base) {
          left.push(item)
        } else {
          equal.push(item)
        }
      }
      if (left.length === k - 1) {
        // 值大于 base 的值刚好有 k - 1 个,那么 base 就是第 k 大的元素
        return base
      } else if (left.length > k - 1) {
        // 值大于 base 的值大于 k - 1 个, 那么第 k 大的元素在 left 内
        return findKthLargest(left, k)
      } else {
        // 值大于 base 的值小于 k - 1 个
        if (left.length + equal.length >= k) {
          // 值在 equal 内直接返回 base
          return base
        } else {
          // 值在 right 内(k 值记得要减去 equal 的长度)
          return findKthLargest(right, k - left.length - equal.length)
        }
      }
    };
  3. 因为题目中数字有边界 -10000 <= nums[i] <= 10000,所以我们可以利用计数排序的方法来寻找。

    typescript 复制代码
    function findKthLargest(nums: number[], k: number): number {
      const arr = new Array(20001).fill(0) // 用于统计数字频率
      const offset = 10000 // 因为有负数我们添加一个偏移量
      for (let num of nums) {
        // 将数字转换成arr数字的下标,对应元素表示出现频次
        arr[num + offset]++
      }
      for (let i = 20001; i >= 0; i--) {
        // 遍历 arr 数组
        if (arr[i] > 0) {
          // 如果遇到出现的数字,就用 k 减去出现的频次
          k -= arr[i]
        }
        if (k <= 0) {
          // k 小于等 0 表示这就是第 k 大的数字
          return i - offset
        }
      }
    };

题目来源:力扣(LeetCode)

相关推荐
学会870上岸华师17 小时前
C 语言程序设计——第一章课后编程题
c语言·开发语言·学习·算法
nashane17 小时前
HarmonyOS 6学习:AI攻略长截图“防抖”与像素级拼接术
学习·华为·harmonyos
小马过河R17 小时前
RAG检索优化策略:系统性四层框架解析
人工智能·python·算法·ai·llm·rag·问答
AI技术控17 小时前
论文解读:AE-TCN-SA——基于自编码器、TCN 与自注意力机制的锂电池内短路诊断方法
人工智能·python·深度学习·算法·机器学习·自然语言处理
ʚ希希ɞ ྀ17 小时前
动态规划基础知识---爬楼梯
算法·动态规划
计算机安禾17 小时前
【c++面向对象编程】第26篇:对象的内存模型:成员变量与成员函数的存储分离
开发语言·c++·算法
贩卖黄昏的熊18 小时前
陕西省ICPC省赛总结
算法
jieyucx18 小时前
Go 语言进阶:构造函数、父子结构体与组合复用详解
服务器·算法·golang·继承·结构体·构造函数
澈20718 小时前
滑动窗口算法:双指针高效解题秘籍
数据结构·c++·算法
渣渣苏18 小时前
硬核拆解 HNSW:亿级向量如何实现毫秒级召回?(上篇)
人工智能·算法·支持向量机·ai·向量数据库·hnsw·智能体