问题描述:
在数组中找到第k大的元素
样例:给出数组[9,3,2,4,8],第三大的元素是4;给出数组 [1,2,3,4,5],第一大的元素是5,第二大的元素是4,第三大的元素是3,以此类推
挑战:要求时间复杂度为O(n),空间复杂度为O(1)
算法设计:
首先对这个数列使用快速排序算法进行从大到小排序,然后再遍历寻找第k大数据。此算法的重点难点应该在于快速排序
public class Model_KthLargestElement {
public static int kthLargestElement(int k, ArrayList<Integer> numbers) {
if(numbers==null||numbers.size()==0||numbers.size()<k){
return 0;
}
//保存最终结果
int result=0;
//保存numbers的大小
int size=numbers.size();
//先使用快速排序方法实现numbers所有元素的从大到小排序
numbers=Quick(numbers,0,numbers.size()-1);
//寻找第一大数,就返回numbers的第一个值
if(k==1){
return numbers.get(0).intValue();
}
//寻找第k大的数字,j为游标,count为第几大
int j=1;
int count=1;
while(j<size&&count!=k){
//相邻两个数字不重复,那么count++
if(numbers.get(j)!=numbers.get(j-1)){
count++;
}
j++;
}
//如果count等于k,那么寻找到第k大数据,否则,遍历完numbers最后一个数字了,还没找到第k大数据,表示,这个数据不存在;
if(count==k){
result=numbers.get(j-1).intValue();
}
return result;
}
//快速排序算法
public static ArrayList<Integer> Quick(ArrayList<Integer> numbers,int left,int right){
if(numbers==null||numbers.size()==0){
return null;
}
//左边游标
int pos=left;
//右边游标
int i=right;
//起到交换作用
int temp=0;
do{
//如果pos后面的数比pos大,或者pos前面的数比pos大,则相交换;
if((i>=pos&&numbers.get(i)>=numbers.get(pos))||(i<pos&&numbers.get(i)<=numbers.get(pos))){
//交换两处对象
temp=numbers.get(pos);
numbers.set(pos, numbers.get(i));
numbers.set(i, temp);
//交换数值时,不能直接写成numbers.get(i)=numbers.get(pos);
//因为numbers.get(i)和numbers.get(pos)都非变量
//开始用了下面代码,想实现两个位置值的交换,出现了越界错误
// numbers.remove(pos);
// numbers.add(pos, numbers.get(i));
// numbers.remove(i);
// numbers.add(i, temp);
//
//交换两处下标
temp=pos;
pos=i;
i=temp;
}
//如果交换后i比pos大,那么i--,否则i++
if(i>pos){
i--;
}else{
i++;
}
}while(i<numbers.size()&&i!=pos);
if(left<pos-1){
Quick(numbers,left,pos-1);
}
if(right>pos+1){
Quick(numbers,pos+1,right);
}
//开始写成如下:如果numbers中无重复数据,还可以运行,一旦,numbers中的数据有重复,例如有i个8,
//那么会出现"StackOverflowError"的错误,因为会在这i个8中反复调用Quick()方法,进栈出栈,最终导致栈溢出
// if(left<pos){StackOverflowError
// Quick(numbers,left,pos-1);
// }
//
// if(right>pos){
// Quick(numbers,pos+1,right);
// }
//
return numbers;
}