文章目录 题目描述 思路 & 代码 快排 基于 Fork / Join 的并发快排 针对 topK 的快排优化 堆排 二刷 
 
大名鼎鼎的TOP K,主要考察排序 快排 & 堆排 没啥好说的,就是快排结束后,返回倒数第K个数字即可。 重点就在于快排的实现了,好久没敲了= =: 原理:使用标志位进行分治的排序,每趟能让标志位的左边都不大于标志位,右边都不小于标志位。 注意点:边界问题、起始位置等,详见代码注释 留个坑:随机化mark,防止退化到 O(n2n^2 n 2  class  Solution  { public  int  findKthLargest ( int [ ]  nums,  int  k)  { myQuickSort ( nums,  0 ,  nums. length -  1 ) ; return  nums[ nums. length -  k] ; } void  myQuickSort ( int [ ]  nums,  int  left,  int  right) { if ( left >=  right) { return ; } int  mark =  nums[ left] ; int  i =  left,  j =  right; while ( i <  j) { while ( i <  j &&  nums[ j]  >=  mark) { j-- ; } while ( i <  j &&  nums[ i]  <=  mark) { i++ ; } if ( i <  j) { int  temp =  nums[ i] ; nums[ i]  =  nums[ j] ; nums[ j]  =  temp; } } nums[ left]  =  nums[ i] ; nums[ i]  =  mark; myQuickSort ( nums,  left,  i -  1 ) ; myQuickSort ( nums,  i +  1 ,  right) ; } 
} 
效率直接从 34s 提高到 8s,太狠了 fork / join简直是快排的指定好兄弟,又好用效率又高。 class  Solution  { public  int  findKthLargest ( int [ ]  nums,  int  k)  { ForkJoinPool  forkJoinPool =  new  ForkJoinPool ( Runtime . getRuntime ( ) . availableProcessors ( ) ) ; forkJoinPool. invoke ( new  SortTask ( nums,  0 ,  nums. length -  1 ) ) ; return  nums[ nums. length -  k] ; } class  SortTask  extends  RecursiveAction  { int [ ]  arr; int  left; int  right; public  SortTask ( int [ ]  arr,  int  left,  int  right)  { this . arr =  arr; this . left =  left; this . right =  right; } @Override protected  void  compute ( )  { if ( left >=  right)  return ; int  mark =  arr[ left] ; int  i =  left,  j =  right; while ( i <  j)  { while ( i <  j &&  arr[ j]  >=  mark)  j-- ; while ( i <  j &&  arr[ i]  <=  mark)  i++ ; if ( i <  j)  { int  temp =  arr[ i] ; arr[ i]  =  arr[ j] ; arr[ j]  =  temp; } } arr[ left]  =  arr[ i] ; arr[ i]  =  mark; SortTask  leftTask =  new  SortTask ( arr,  left,  i -  1 ) ; SortTask  rightTask =  new  SortTask ( arr,  i +  1 ,  right) ; leftTask. fork ( ) ; rightTask. fork ( ) ; leftTask. join ( ) ; rightTask. join ( ) ; } } 
} 
能达到 Fork / Join 的效率,并且不需要额外线程资源 关键在于局部有序 ,对于 topK 问题来说,我们只关心第K个最大元素。 因此实际上并不需要做到全局有序,可以在每次递归时都只选择一个区间进行递归 时间复杂度:等待有缘人补充  class  Solution  { public  int  findKthLargest ( int [ ]  nums,  int  k)  { sort ( nums,  0 ,  nums. length -  1 ,  k) ; return  nums[ nums. length -  k] ; } void  sort ( int [ ]  nums,  int  left,  int  right,  int  k)  { if ( left >=  right)  return ; int  mark =  nums[ left] ; int  i =  left,  j =  right; while ( i <  j)  { while ( i <  j &&  nums[ j]  >=  mark)  j-- ; while ( i <  j &&  nums[ i]  <=  mark)  i++ ; if ( i <  j)  { int  temp =  nums[ i] ; nums[ i]  =  nums[ j] ; nums[ j]  =  temp; } } nums[ left]  =  nums[ i] ; nums[ i]  =  mark; int  rightNums =  right -  i +  1 ; if ( rightNums <  k)  sort ( nums,  left,  i -  1 ,  k -  rightNums) ;  else  sort ( nums,  i +  1 ,  right,  k) ;  } 
} 
可以直接用堆排,也可以针对题目变形一下(会快很多)。这里都贴一下 三个主要函数:heapify、buildTree 与 myHeapSort 逻辑上是完全二叉树,通过数组实现 Parent = (son - 1) / 2 Son1 = Parent * 2 + 1。 Son2 = Son1 + 1。 heapify:递归向下 buildTree:从下(第一个Parent)往上遍历进行heapify myHeapSort:每次都取最值,与结尾交换。然后缩小范围继续。 class  Solution  { public  int  findKthLargest ( int [ ]  nums,  int  k)  { myHeapSort ( nums) ; return  nums[ nums. length -  k] ; } void  swap ( int [ ]  nums,  int  one,  int  two) { int  temp =  nums[ one] ; nums[ one]  =  nums[ two] ; nums[ two]  =  temp; } void  heapify ( int [ ]  nums,  int  n,  int  now) { if ( now >=  n) { return ; } int  maxIndex =  now; int  son1 =  2  *  now +  1 ; int  son2 =  son1 +  1 ; if ( son1 <  n &&  nums[ maxIndex]  <  nums[ son1] ) { maxIndex =  son1; } if ( son2 <  n &&  nums[ maxIndex]  <  nums[ son2] ) { maxIndex =  son2; } if ( maxIndex !=  now) { swap ( nums,  now,  maxIndex) ; heapify ( nums,  n,  maxIndex) ; } } void  buildTree ( int [ ]  nums) { int  lastNode =  nums. length -  1 ; int  lastParent =  ( lastNode -  1 )  /  2 ; for ( ;  lastNode >=  0 ;  lastNode-- ) { heapify ( nums,  nums. length,  lastNode) ; } } void  myHeapSort ( int [ ]  nums) { buildTree ( nums) ; int  lastNode =  nums. length -  1 ; for ( int  i =  lastNode;  i >=  0 ;  i-- ) { swap ( nums,  0 ,  i) ; heapify ( nums,  i,  0 ) ; } } 
} 
class  Solution  { public  int  findKthLargest ( int [ ]  nums,  int  k)  { return  myHeapSort ( nums,  k) ; } void  swap ( int [ ]  nums,  int  one,  int  two) { int  temp =  nums[ one] ; nums[ one]  =  nums[ two] ; nums[ two]  =  temp; } void  heapify ( int [ ]  nums,  int  n,  int  now) { if ( now >=  n) { return ; } int  maxIndex =  now; int  son1 =  2  *  now +  1 ; int  son2 =  son1 +  1 ; if ( son1 <  n &&  nums[ maxIndex]  <  nums[ son1] ) { maxIndex =  son1; } if ( son2 <  n &&  nums[ maxIndex]  <  nums[ son2] ) { maxIndex =  son2; } if ( maxIndex !=  now) { swap ( nums,  now,  maxIndex) ; heapify ( nums,  n,  maxIndex) ; } } void  buildTree ( int [ ]  nums) { int  lastNode =  nums. length -  1 ; int  lastParent =  ( lastNode -  1 )  /  2 ; for ( ;  lastNode >=  0 ;  lastNode-- ) { heapify ( nums,  nums. length,  lastNode) ; } } int  myHeapSort ( int [ ]  nums,  int  k) { buildTree ( nums) ; int  lastNode =  nums. length -  1 ; for ( int  i =  lastNode;  i >=  0 ;  i-- ,  k-- ) { if ( k ==  1 ) { return  nums[ 0 ] ; } swap ( nums,  0 ,  i) ; heapify ( nums,  i,  0 ) ; } return  - 1 ; } 
} 
while ( i <  j) { while ( i <  j &&  nums[ j]  >=  mark)  j-- ; while ( i <  j &&  nums[ i]  <=  mark)  i++ ; 
class  Solution  { public  int  findKthLargest ( int [ ]  nums,  int  k)  { heapSort ( nums) ; return  nums[ nums. length -  k] ; } void  heapSort ( int [ ]  nums)  { buildTree ( nums) ; for ( int  i =  nums. length -  1 ;  i >=  0 ;  i-- )  { swap ( nums,  i,  0 ) ; heapify ( nums,  i,  0 ) ; } } void  buildTree ( int [ ]  nums)  { for ( int  son =  nums. length -  1 ;  son >=  0 ;  son-- )  { heapify ( nums,  nums. length,  son) ; } } void  heapify ( int [ ]  nums,  int  length,  int  nowIndex)  { if ( nowIndex >=  length)  { return ; } int  son1 =  nowIndex *  2  +  1 ; int  son2 =  son1 +  1 ; int  maxIndex =  nowIndex; if ( son1 <  length &&  nums[ son1]  >  nums[ maxIndex] )  { maxIndex =  son1; } if ( son2 <  length &&  nums[ son2]  >  nums[ maxIndex] )  { maxIndex =  son2; } if ( maxIndex !=  nowIndex)  { swap ( nums,  maxIndex,  nowIndex) ; heapify ( nums,  length,  maxIndex) ; } } void  swap ( int [ ]  nums,  int  left,  int  right)  { int  temp =  nums[ left] ; nums[ left]  =  nums[ right] ; nums[ right]  =  temp; } 
}