`

O(n)复杂度,求数组中第2大的数

 
阅读更多

为什么我反对纯算法面试

提及一条算法题目,查找一个数组中第二大的数。

 

第二大数,直接想到的是,先遍历一次数组,把最大的取出来。然后再遍历一次,把最大的取出来。总耗费时间复杂度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)的快排怎么写了,呵呵,只记得用了分治递归的思想。嗯,下次我也尝试不看书的情况写个快排。

 

各位看官,不知道有没有其他方法,请不吝笔墨,大书特书。

 

 

3
2
分享到:
评论
8 楼 libofeng 2013-04-16  
第一个解法简单明了
7 楼 ansjsun 2013-04-16  
lazy_ 写道
ansjsun 写道
大概看了下代码...
这么排啊...其实答案应该是堆排...

第二大是 O(2*logn)  = O(n)


不对呀。你构建一个堆也花了O(N*logN)。期待你的回复,最好有代码。



全排序是O(N*logN).

如果只找出第n大 就是 O(n*logN) ;

代码网上好多的...你得看看堆的性质..每次弹出一个最大的...
6 楼 lazy_ 2013-04-16  
ansjsun 写道
大概看了下代码...
这么排啊...其实答案应该是堆排...

第二大是 O(2*logn)  = O(n)


不对呀。你构建一个堆也花了O(N*logN)。期待你的回复,最好有代码。
5 楼 chinaagan 2013-04-15  
ansjsun 写道
大概看了下代码...
这么排啊...其实答案应该是堆排...

第二大是 O(2*logn)  = O(n)

不错
4 楼 ansjsun 2013-04-15  
大概看了下代码...
这么排啊...其实答案应该是堆排...

第二大是 O(2*logn)  = O(n)
3 楼 kidneyball 2013-04-15  
robin_liang 写道
O(n + n -1)和O(n)有区别吗?


在算法复杂度上没区别,在转化为实际程序后执行效率上有区别。算法复杂度只是一个用来衡量算法运算量跟输入数据规模的比例关系的工具(例如是无关,或是线性关系,或是指数关系),不等同于算法所对应程序的实际执行效率。算法复杂度相同的算法在写成实际程序后执行效率是可能有区别的。

前几天还在微博上跟前某创新院的某名博扯这个问题……他用一段O(n)的预处理弄出来一个链表,然后做了一个O(n)的顺序搜索。我用一段O(n)的预处理弄出来一个数组,然后做了一个O(logn)的二分搜索。他楞是要说我们的两种处理的时间是一致的(原话是我的做法在时间上没有优化),因为O(n+n) = O(n + logn) = O(n)。我问他:那是不是做了一次O(n)的预处理后,后面再跟一万个O(n),和把这一万个O(n)都改成O(logn)时间是一样的? 他答:本来就是这样……

2 楼 backkom1982 2013-04-15  
求第N大的数,都可以在O(n)复杂度能完成。

先分成每组包含N个的多个小组,N是大于等于5的奇数,然后再会分而治之的方法寻找第N大的数。

具体思路可见:
http://www.shrekwang.com/article/52001/%E5%AF%BB%E6%89%BE%E7%AC%ACk%E5%A4%A7%E7%9A%84%E6%95%B0%E7%9A%84O(n)%E7%AE%97%E6%B3%95
1 楼 robin_liang 2013-04-15  
O(n + n -1)和O(n)有区别吗?

相关推荐

    时间复杂度为O(n)的找中位数算法源代码

    2. **遍历数组**:从数组的第二个元素开始遍历,对于每一个元素`a[i]`,根据其与当前中位数估计值`mid`的比较结果更新`mid`、`mid_left`和`mid_right`的值。 - 如果`a[i] &gt; mid`且`i`为偶数,那么: - 如果`a[i] ...

    取数组中的第2大值

    "取数组中的第2大值"是一个非常明确的标题,它告诉我们需要从给定的数组中找出第二大的元素的下标和值。这个问题非常常见,在实际编程中经常会遇到这种情况。 描述解释 "c语言实现取数组中的第2大值"是标题的详细...

    深入线性时间复杂度求数组中第K大数的方法详解

    这篇文章将详细介绍如何在O(n)的时间复杂度内找到数组中的第K大数。 首先,理解这个问题的核心是利用快速排序的分治思想。快速排序通常用于对整个数组进行排序,但在这里我们并不需要完全排序,而是只需要找到第K大...

    数组和链表的时间复杂度 数组和链表.pdf

    2. 随机访问:数组可以随机访问,这意味着我们可以通过索引直接访问数组中的任何元素。这是因为数组的元素在内存中是连续的,因此我们可以通过索引来计算元素的地址。例如,vector的随机访问可以通过iterator i = v....

    数据结构(JAVA)求一个含有n个整数元素的数组a0..n-1中的最大元素

    然后,通过一个for循环从数组的第二个元素开始遍历,如果当前元素大于已知的最大值,就更新最大值。当遍历完整个数组后,返回找到的最大值。 这种方法虽然简单,但效率并不高,因为它的时间复杂度是O(n),其中n是...

    计算整形数组中第k小的数

    选择排序的时间复杂度为O(n^2),在数据量较大时效率较低。为了提高性能,可以考虑以下几种优化方案: 1. **使用更高效的排序算法**:如快速排序或归并排序,它们的时间复杂度通常为O(n log n)。 2. **部分排序**:...

    求解找到数组A[1..n]中元素的最大值和次最大值(本小题以数组元素的比较为标准操作)的算法,并分析其最坏情况的时间复杂度。

    - **遍历**:从数组的第二个元素开始,逐个与当前的最大值和次最大值进行比较。 - **更新逻辑**: - 如果当前元素大于最大值\( x \),则将\( x \)的值赋给\( y \),并将当前元素赋值给\( x \)。 - 如果当前元素...

    自定义数组中寻找最大元素位置

    - 程序的时间复杂度为O(n*m),其中n是行数,m是列数。这是因为程序需要遍历数组的每一个元素。 - 空间复杂度为O(1),除了输入数组之外,只使用了固定的几个变量来存储中间结果。 5. **扩展性**: - 可以通过修改...

    数据结构(JAVA) 将含有n个整数元素的数组a0..n-1循环右移m位,要求算法的空间复杂度为O(1)

    在这个问题中,我们需要确保算法的空间复杂度为O(1),这意味着我们不能使用额外的大规模存储空间,只能在原数组上进行操作。 首先,我们要理解循环右移的概念。假设有一个数组`a[0..n-1]`,循环右移m位意味着数组的...

    Java数组排序总结(冒泡_选择_插入_希尔)__递归算法的复杂度

    插入排序在小规模或者部分有序的数据中表现良好,其最好情况(已排序数组)的时间复杂度为O(n),最坏情况(反序数组)为O(n^2),平均情况为O(n^2)。 **希尔排序**是插入排序的一种优化版本,通过设置一个增量序列,...

    C++求二维数组中的最大值和最小值的方法

    这段代码的效率相当高,因为它只需要遍历一次数组,时间复杂度为O(n),其中n是数组中的元素总数。此外,由于我们直接对数组进行操作,没有使用额外的数据结构,所以空间复杂度为O(1)。 总之,通过使用嵌套循环和...

    求一个数组最小的两个数的下标

    2. 遍历数组,从第二个元素(下标为1)开始。 3. 对于每个元素,如果它的值小于当前的最小值,更新minIndex1为当前元素的下标;如果它的值大于等于最小值但小于当前的次小值,更新minIndex2。 4. 遍历完成后,...

    数对之差的最大值

    一次遍历的时间复杂度为O(n),其中n是数组的长度,因为只需要遍历数组一次。而排序会引入额外的时间开销,如果使用快速排序、归并排序等高效排序算法,时间复杂度大约为O(n log n)。但是一旦排序完成,查找最大差值...

    用数组求N的阶乘,可以运行

    - 计算效率不高,因为每次迭代都需要乘以前一个元素,对于大规模数据,时间复杂度较高,为O(N)。 在实际应用中,我们还可以考虑其他优化策略,如使用动态规划减少不必要的计算,或者使用更高效的数据结构,如链表。...

    python 实现在无序数组中找到中位数方法

    否则,根据左侧数组长度与`(n-1)/2`的关系,确定中位数在右侧还是左侧,并在相应一侧继续查找,直至找到中位数。这种方法的平均时间复杂度为O(n)。 3. **程序实现** - 定义一个名为`Solution`的类,其中包含一个`...

    解决数组中出现相同数的情况

    1. **遍历检查**:最直观的方法是两层循环遍历数组,第一层遍历数组元素,第二层检查其余元素是否有相同的值。这种方法的时间复杂度为O(n^2),效率较低,但实现简单。 2. **排序后查找**:可以先对数组进行排序,...

    求子数组最大和

    这个问题的一个著名解决方案是Kadane's Algorithm(卡丹算法),它具有线性时间复杂度,即O(n),其中n是数组的长度。 首先,我们需要理解什么是子数组。在数组中,子数组是指从数组中选取任意连续的一段元素形成的...

    算法-数组排序 按数组内数字大小排序 取得最大值或最小值.rar

    2. 查找第二大、第三小等值: - 遍历法:在已排序数组中,找到最大值后,再遍历一次数组找到次大值。 - 优先队列(堆):使用最大堆结构,可以快速找到最大的k个元素。 三、排序算法的时间复杂度和稳定性 时间...

    如何寻找数组中的第二大数

    这两种方法都是线性时间复杂度,即 O(n),其中 n 是数组的长度。虽然在最坏的情况下都需要遍历整个数组,但它们都避免了使用额外的数据结构(如堆或排序),因此在空间效率上表现良好。对于小规模的数据,这种效率是...

Global site tag (gtag.js) - Google Analytics