您的位置:首页 > 其它

从大小为N的数组中选出第k小的数据

2014-06-18 23:16 232 查看
这个是从《编程珠玑(续)》的最后一章看到的,感觉相当的经典,特此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(int j=low+1;j<=high;){
if( list[j]<list[low] ){
swap(list,i,j);
i++;
j++;
}else{
j++;
}
}
swap(list,low,i-1);
if(i-1==k)
return list[i-1];
else if(i-1<k)
return subSolve(list,i,high,k);
else
return subSolve(list,low,i-2,k);
}

//交换数组的元素
public void swap(int[] list,int a,int b){
int temp = list[a];
list[a] = list[b];
list[b] = temp;
}

public static void main(String[] args){
System.out.println(new Solution().solve(new int[]{2,1,5,4,3,6,9,100,-1,0,-100},6));
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 递归
相关文章推荐