查找第N大的数
2023年1月3日 · 206 字 · 1 分钟
在给定的序列中查找第N大的数,朴素做法是对序列排序,然后根据索引直接查询,时间复杂度为$O(nlogn)$。
本文介绍一种在$O(n)$的时间复杂度查询第N大的数的算法。
算法
算法思路就是定义标志变量,然后遍历数组,根据标志变量和当前数组变量的大小更新标志变量,最后根据情况返回标志变量。
示例:查找第2大的数
定义$first$和$second$分别存储最大和次大,然后遍历数组时更新即可。
/**
* 查找第二大的数字
*/
public class SecondMaximumNumber {
public int secondMaximumNumber(int[] nums) {
// 最大数
var first = Integer.MIN_VALUE;
// 次大数
var second = Integer.MIN_VALUE;
for (var num : nums) {
// 当前数字比最大数还大,最大数更新为当前数字,原来的最大数更新为第2大
if (num >= first) {
second = first;
first = num;
} else if (num >= second) { // 当前数字小于最大,但是大于第2大,更新第2大
second = num;
}
}
return second;
}
public static void main(String[] args) {
var nums = new int[]{1, 3, 2, 8, 5};
var s = new SecondMaximumNumber();
System.out.println(s.secondMaximumNumber(nums));
}
}
示例:查找第3大的数
Leetcode: 第三大的数
原理和查第2大的数想通,定义$first$,$second$,$third$三个变量,然后遍历$nums$
- 若$num > first$,则$second$赋值给$third$,$first$赋值给$second$,$num$赋值给$first$
- 若$num < first$且 $num > second$,则$second$赋值给$third$,$num$赋值给$second$
- 若$num < second$且$num > third$,则$num$赋值给$third$
最后根据题意返回$third$或者$first$即可。
class Solution3 {
// 三个变量
public int thirdMax(int[] nums) {
var first = Long.MIN_VALUE;
var second = first;
var third = second;
for (var num : nums) {
if (num > first) { // 如果num>最大值,原来的最大变次大,原来的次大变三大, 当前边最大
third = second;
second = first;
first = num;
} else if (num < first && num > second) { // 小于最大,但是大于第二, 第二变第三,当前边第二
third = second;
second = num;
} else if (num < second && num > third) { // 小于第二,但是大于第三
third = num;
}
}
return (int) (third == Long.MIN_VALUE ? first : third);
}
}
时间复杂度:$O(n)$,$n$是数组长度,仅需遍历一次。
空间复杂度: $O(1)$,仅需使用3个变量。