news 2026/8/22 12:01:26

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
分治题目:数组中的第 K 个最大元素

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
  • 解法
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

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

出处:215. 数组中的第 K 个最大元素

难度

6 级

题目描述

要求

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

注意需要返回的是数组排序后的第k \texttt{k}k个最大的元素,不是第k \texttt{k}k个不同的元素。

要求时间复杂度是O(n) \texttt{O(n)}O(n)

示例

示例 1:

输入:nums = [3,2,1,5,6,4], k = 2 \texttt{nums = [3,2,1,5,6,4], k = 2}nums = [3,2,1,5,6,4], k = 2
输出:5 \texttt{5}5

示例 2:

输入:nums = [3,2,3,1,2,4,5,5,6], k = 4 \texttt{nums = [3,2,3,1,2,4,5,5,6], k = 4}nums = [3,2,3,1,2,4,5,5,6], k = 4
输出:4 \texttt{4}4

数据范围

  • 1 ≤ k ≤ nums.length ≤ 10 5 \texttt{1} \le \texttt{k} \le \texttt{nums.length} \le \texttt{10}^\texttt{5}1knums.length105
  • -10 4 ≤ nums[i] ≤ 10 4 \texttt{-10}^\texttt{4} \le \texttt{nums[i]} \le \texttt{10}^\texttt{4}-104nums[i]104

解法

思路和算法

在长度为n nn的数组中寻找第k kk个最大的元素,最简单的做法是将数组排序,然后返回第k kk个最大的元素,该做法的时间复杂度是O ( n log ⁡ n ) O(n \log n)O(nlogn)

为了将时间复杂度降低到O ( n ) O(n)O(n),需要使用快速选择算法。快速选择算法和快速排序算法相似,是分治的应用。由于题目要求寻找第k kk个最大的元素,因此考虑将数组降序排序,排序后的数组的下标k − 1 k - 1k1处元素即为第k kk个最大的元素。

快速选择算法的操作包括选择基准元素和分区,做法如下。

  1. 选择基准元素。可以选择数组的首个元素作为基准元素,也可以在数组中随机选择一个元素作为基准元素并将基准元素与数组的首个元素交换位置,此时数组的首个元素为基准元素。

  2. 分区。分区的含义是将数组分成两个子数组,基准元素左侧子数组的元素都大于等于基准元素,基准元素右侧子数组的元素都小于基准元素。具体做法如下。

    1. start \textit{start}startend \textit{end}end分别表示当前数组的开始下标和结束下标,初始化两个指针low = start + 1 \textit{low} = \textit{start} + 1low=start+1high = end \textit{high} = \textit{end}high=end

    2. low \textit{low}low从左往右遍历,直到遇到小于基准元素的元素;将high \textit{high}high从右往左遍历,直到遇到大于等于基准元素的元素。此时如果low < high \textit{low} < \textit{high}low<high,则交换low \textit{low}lowhigh \textit{high}high处的元素。重复该操作,直到low ≥ high \textit{low} \ge \textit{high}lowhigh时结束该操作。

    3. high \textit{high}high从右往左遍历,直到遇到大于等于基准元素的元素。

    4. 此时high \textit{high}high指向基准元素应该放置下标的位置。如果high > start \textit{high} > \textit{start}high>start,则交换start \textit{start}starthigh \textit{high}high处的元素。

  3. pivotIndex \textit{pivotIndex}pivotIndex表示分区之后基准元素所在下标。根据pivotIndex \textit{pivotIndex}pivotIndexk − 1 k - 1k1的大小关系,执行如下操作。

    • 如果pivotIndex = k − 1 \textit{pivotIndex} = k - 1pivotIndex=k1,则此时的基准元素即为第k kk个最大的元素,返回下标pivotIndex \textit{pivotIndex}pivotIndex处的元素。

    • 如果pivotIndex > k − 1 \textit{pivotIndex} > k - 1pivotIndex>k1,则下标pivotIndex \textit{pivotIndex}pivotIndex处的元素小于等于第k kk个最大的元素,在下标范围[ start , pivotIndex − 1 ] [\textit{start}, \textit{pivotIndex} - 1][start,pivotIndex1]中继续寻找第k kk个最大的元素。如果数组中存在多个基准元素,则可以跳过连续基准元素,从而降低时间复杂度。

    • 如果pivotIndex < k − 1 \textit{pivotIndex} < k - 1pivotIndex<k1,则下标pivotIndex \textit{pivotIndex}pivotIndex处的元素大于等于第k kk个最大的元素,在下标范围[ pivotIndex + 1 , end ] [\textit{pivotIndex} + 1, \textit{end}][pivotIndex+1,end]中继续寻找第k kk个最大的元素。

快速排序算法的平均时间复杂度是O ( n log ⁡ n ) O(n \log n)O(nlogn),快速选择算法在每次分区之后都可以排除不可能包含第k kk个最大元素的子数组,因此平均时间复杂度低于快速排序算法。

平均情况下,快速选择算法在每次分区之后都可以排除数组中的一半元素,递归调用层数是O ( log ⁡ n ) O(\log n)O(logn),时间复杂度是O ( n ) O(n)O(n),空间复杂度是O ( log ⁡ n ) O(\log n)O(logn)。最差情况下,快速选择算法在每次分区时选择的基准元素都是数组中的最小值或最大值,递归调用层数是O ( n ) O(n)O(n),时间复杂度是O ( n 2 ) O(n^2)O(n2),空间复杂度是O ( n ) O(n)O(n)

使用随机选择基准元素的做法可以最大程度避免最差情况的发生,达到O ( n ) O(n)O(n)的时间复杂度。

代码

classSolution{publicintfindKthLargest(int[]nums,intk){returnquickSelect(nums,k-1,0,nums.length-1);}publicintquickSelect(int[]nums,intindex,intstart,intend){intpivotIndex=partition(nums,start,end);if(pivotIndex==index){returnnums[pivotIndex];}elseif(pivotIndex>index){while(pivotIndex-1>index&&nums[pivotIndex-1]==nums[pivotIndex]){pivotIndex--;}returnquickSelect(nums,index,start,pivotIndex-1);}else{returnquickSelect(nums,index,pivotIndex+1,end);}}publicintpartition(int[]nums,intstart,intend){intrandomIndex=start+(int)(Math.random()*(end-start+1));swap(nums,start,randomIndex);intpivot=nums[start];intlow=start,high=end;while(low<high){while(low<high&&nums[low]>=pivot){low++;}while(low<high&&nums[high]<pivot){high--;}if(low<high){swap(nums,low,high);}}while(high>start&&nums[high]<pivot){high--;}if(high>start){swap(nums,start,high);}returnhigh;}publicvoidswap(int[]nums,intindex1,intindex2){inttemp=nums[index1];nums[index1]=nums[index2];nums[index2]=temp;}}

复杂度分析

  • 时间复杂度:平均情况是O ( n ) O(n)O(n),最差情况是O ( n 2 ) O(n^2)O(n2),其中n nn是数组nums \textit{nums}nums的长度。快速选择算法的平均时间复杂度是O ( n ) O(n)O(n),最差时间复杂度是O ( n 2 ) O(n^2)O(n2)

  • 空间复杂度:平均情况是O ( log ⁡ n ) O(\log n)O(logn),最差情况是O ( n ) O(n)O(n),其中n nn是数组nums \textit{nums}nums的长度。空间复杂度取决于递归调用层数。平均情况下,递归调用层数是O ( log ⁡ n ) O(\log n)O(logn),快速选择算法的空间复杂度是O ( log ⁡ n ) O(\log n)O(logn)。最差情况下,递归调用层数是O ( n ) O(n)O(n),快速选择算法的空间复杂度是O ( n ) O(n)O(n)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/22 12:00:57

B/S端界面控件DevExtreme中文指南——如何自定义应用主题?

DevExtreme拥有高性能的HTML5 / JavaScript小部件集合&#xff0c;使您可以利用现代Web开发堆栈&#xff08;包括React&#xff0c;Angular&#xff0c;ASP.NET Core&#xff0c;jQuery&#xff0c;Knockout等&#xff09;构建交互式的Web应用程序&#xff0c;该套件附带功能齐…

作者头像 李华
网站建设 2026/8/22 12:00:34

芯片DFT可测性设计入门与核心概念

芯片DFT可测性设计入门与核心概念 在一颗动辄百亿晶体管的现代SoC中,如果不在设计阶段就为"测试"留好通路,那么这颗芯片在出厂时将如同一个无法打开的黑盒——你永远无法确认它是否真的能正常工作。DFT(Design for Test,可测性设计)正是为解决这一根本性矛盾而生…

作者头像 李华
网站建设 2026/8/22 12:00:16

全面UI组件库Telerik——为驱动制造业生产商提升生产效率赋能

制造商背景Parker中文名称派克&#xff08;派克汉尼汾的简称&#xff09;Parker Hannifin&#xff0c;是全球领先的运动和控制技术与系统多元化制造商&#xff0c;为广泛的传动控制、工业和航空市场提供精准解决方案&#xff0c;现已成为世界上最大的专业生产和销售各种制冷空调…

作者头像 李华
网站建设 2026/8/22 11:58:15

从TextRank到BART:NLP文本摘要技术原理与实战指南

在信息爆炸的时代&#xff0c;我们每天都被海量的文本信息包围——新闻、报告、论文、邮件、社交媒体动态。如何快速、准确地抓住一篇文章的核心思想&#xff0c;成为了提升信息处理效率的关键。文本摘要技术&#xff0c;作为自然语言处理&#xff08;NLP&#xff09;领域的一项…

作者头像 李华
网站建设 2026/8/22 11:57:40

NodeJS之NPM模块管理器

文章目录1 npm模块管理器1.1 npm简介1.2 修改全局包安装目录1.3 npm常用命令1.3.1 npm init1.3.2 npm set1.3.3 npm info1.3.4 npm search1.3.5 npm list1.3.6 install & add1.3.6.1 npm install1.3.6.2 npm add1.3.7 npm update&#xff0c;npm uninstall1.3.8 npm run1.3…

作者头像 李华
网站建设 2026/8/22 11:50:45

十分钟搭建个人博客:浪浪云与Halo的免运维部署实践

之前想搭建个人博客&#xff0c;要么得折腾服务器、域名、备案&#xff0c;要么得忍受免费平台的广告和限制&#xff0c;技术门槛和精力成本都不低。最近发现“浪浪云”和“Halo”的组合&#xff0c;简直是个人站长的福音&#xff0c;从零到上线一个功能完整、界面美观的博客&a…

作者头像 李华