提及一条算法题目,查找一个数组中第二大的数。
第二大数,直接想到的是,先遍历一次数组,把最大的取出来。然后再遍历一次,把最大的取出来。总耗费时间复杂度O(n + n -1)
还有没有其他O(n)的算法呢?
先挖坑,在填坑,都到凌晨2点了,明天想下
早上起来,想了下,跟上次连续子数组的思维差不多,用两个数字保存最大的两个数值,大的放前面,第二大的放后面,然后在遍历过程中穷举各种情况即可。
public class kmax{
public static void main(String[] args){
int[] a = new int[]{1,3,-2,32,-3,5};
System.out.println(get2ndMax(a));
}
public static int get2ndMax(int[] a){
//max[0]存放最大值,max[1]存放第二最大值
int[] max = new int[2];
if(a[0]>a[1]){
max[0] = a[0];
max[1] = a[1];
}else{
max[0] = a[1];
max[1] = a[0];
}
for(int i=2;i<a.length;i++){
//穷举,其实就2种情况
if(a[i]>max[0]){
max[1] = max[0];
max[0] = a[i];
}else if(a[i]>max[1]){
max[1] = a[i];
}
}
return max[1];
}
}
去中大打完球回来,除了一身汗,把想到的位图方法也写上吧。编程珠玑中使用位图排序实现了O(n)的排 序,让我大开眼界,原来在特定条件下,O(n)排序也是可能的。既然O(N)的排序都有了,查找第2大的数字也没问题。假定数组的数字都是整数,上限是 MAX,下限是MIN。算法的复杂度是O(2*(MAX-MIN))。
public class BitmapKmax{
public static void main(String[] args){
int[] a = new int[]{-20,-29,32,99,29,10,39,42,28};
System.out.println(get2ndMax(a,-100,100));
}
public static int get2ndMax(int[] a, final int MIN, final int MAX){
if(a.length<2){
throw new IllegalArgumentException("array must contain at least 2 elements");
}
int secondMax = 0;
byte[] byteArr = new byte[(MAX-MIN)/8 + 1];
for (int i=0; i<a.length; i++) {
int v = a[i]-MIN;
int index = v/8;
int v2 = v%8;
byteArr[index] = (byte)(byteArr[index] | (1<<v2));
}
for (int i=0, count=0; i<byteArr.length; i++) {
if(byteArr[i]!=0){
for(int j=0;j<8;j++){
if(0 != (byteArr[i] & (1<<j))){
count++;
}
if(2 == count){
secondMax = i*8 + j;
break;
}
}
if(2 == count){
break;
}
}
}
return secondMax+MIN;
}
}
至于他文章中所说的那个同学没有用O(n)的方法去做,而是用排序,我也挺佩服的。说实话,我也忘了O(nlogn)的快排怎么写了,呵呵,只记得用了分治递归的思想。嗯,下次我也尝试不看书的情况写个快排。
各位看官,不知道有没有其他方法,请不吝笔墨,大书特书。