这个是从《编程珠玑(续)》的最后一章看到的,感觉相当的经典,特此mark一下。
话说一拿到这个题目直接想到的是快排之类的O(NlogN)复杂度的算法:即先排好序,再得到。时间复杂度O(NlogN)实际上是每一层的递归对N个数进行了操作,一共是logN层。下面介绍的算法类似于快排,但是和快排又有区别,每一层并不是操作了N个数,而是对其中的部分进行操作(感觉像是类似剪枝的过程),所以降低了时间复杂度。
算法概要:每一次递归对数组的部分(原始数组记为a,low表示此时部分数组的最小下标,high表示此时部分数组的最大下标)进行操作,第一次递归是整个数组。每一次递归都对数组的部分选定一个数(任意选,简单处理可以选第一个数a[low]),然后将a分为两部分,小于a[low]的和大于a[low]的,将a[low]作为边界放在两部分的中间,然后可以得到此时a[low]的下标index。若index==k,结束递归;若index<k,下一次迭代的范围是index+1到high;若index>k,下一次迭代的范围是low到index-1。
分析(平均)时间复杂度:N+N/2+N/4+N/8+......+1<2N,所以时间复杂度为O(N)。
public class Solution {
//返回结果 k代表第k小的数 k从1开始
public int solve(int[] list,int k){
k = k-1;
if( k>=0 && k<=list.length-1 )
return subSolve(list,0,list.length-1,k);
else
return Integer.MIN_VALUE;
}
//返回查找的结果 i是当前的分界线,j是一直增长的
public int subSolve(int[] list,int low,int high,int k){
int i = low+1;
for(in