如何找出数组中第二大的数?(一道面试算法题的思考)
前两天面试的过程中问道的一个算法题,题目不算难,但是一步步分析优化的过程我觉得挺受启发,所以拿出来分享一下。
题目要求很简单,就是找出给定数组中第二大的数,略微思考之后我给出了下面的答案,即使用执行两次迭代,使用冒泡排序将两个最大值移动到数组末尾,数组中倒数第二个值即为要求的第二大的值。
public static int getSecondBiggestNum(int []arr) { int temp; for (int j = 0; j < 2; j++) { for (int i = 0; i < arr.Length - 1; i++) { if (arr[i] > arr[i + 1]) { temp = arr[i]; arr[i] = arr[i + 1]; arr[i + 1] = temp; } } } return arr[arr.Length - 2]; }
时间复杂度为2n,效率还可以,使用数组{8,6,2,7,3}来测试返回结果也没有问题,但是忽略了一个细节,题目中没有说明数组中的值是不重复的,所以对于{8,8,6,2,7,3}来说,返回结果就是错误的。
于是我考虑可以在两次迭代之后判断最后两个值是否相等,如果相等的话再继续第三次冒泡排序,这样以此类推,总能找到第二大的,但是很快这种想法被否定了,因为在极端情况下(如{8,8,8,8,8,3})算法的复杂度是n2,效率太低。
那么接着分析,首先肯定是要有一轮迭代找出最大值的,那么既然已经找出最大值了,是不是可以在第二轮迭代中直接将数组中其他小于最大值的数移到一个临时数组中呢,然后对临时数组再做一次冒泡就可以求出最大值,时间复杂度大概是3n,貌似可以接受。
public static int getSecondBiggestNum(int []arr) { int temp; int []tempArr = new int[arr.Length-1]; for (int i = 0; i < arr.Length - 1; i++) { if (arr[i] > arr[i + 1]) { temp = arr[i]; arr[i] = arr[i + 1]; arr[i + 1] = temp; } } for (int i = 0; i < arr.Length - 1; i++) { if (arr[i] != arr[arr.Length-1]) { tempArr[i] = arr[i]; } } for (int i = 0; i < tempArr.Length - 1; i++) { if (tempArr[i] > tempArr[i + 1]) { temp = tempArr[i]; tempArr[i] = tempArr[i + 1]; tempArr[i + 1] = temp; } } return tempArr[tempArr.Length - 1]; }
但是新的问题又来了,因为引入了新的临时数组变量,增加了空间复杂度。那么不用临时数组是不是可以呢?既然最大值已经求出来了,那么完全可以在第二轮迭代的时候通过与最大值的比较得出第二大的值。
public static int getSecondBiggestNum(int []arr) { int temp =0; //第一轮迭代求最大值 for (int i = 0; i < arr.Length - 1; i++) { if (arr[i] > arr[i + 1]) { temp = arr[i]; arr[i] = arr[i + 1]; arr[i + 1] = temp; } } //第二轮迭代求第二大值 for (int i = 0; i < arr.Length - 1; i++) { if (temp <arr[i] && arr[i] != arr[arr.Length-1] )
{
temp = arr[i];
}
}
return temp;
}
貌似可以了,但是仔细看第一次迭代,只是求最大值,没有必要进行排序,排序也是要耗费内存降低效率的,所以再定义一个临时变量记录最大值。
public static int getSecondBiggestNum(int []arr) { int temp =0; int biggestNum = arr[0]; //第一轮迭代求最大值 for (int i = 0; i < arr.Length ; i++) { if (biggestNum < arr[i]) biggestNum = arr[i]; } //第二轮迭代求第二大值 for (int i = 0; i < arr.Length; i++) { if (temp < arr[i] && arr[i] != biggestNum) { temp = arr[i]; } } return temp; }
这次终于可以了,但是使用{1,1,1,1,1,1}这种数组验证时,返回了0,明显是错误的值,这时候应该给出提示,按照具体需求返回一个值,具体的代码这里就不再写了。
这道题确实不难实现,很容易找到思路,但是实现功能是一方面,分析还有没有可优化的地方是另一方面,而这个分析优化的过程也是自己不断进步的过程。
(委托系列文章稍后会继续)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库