题目描述:
给定数组arr,最多只能遍历该数组一次,求出数组的第二大元素。
用两个变量即可实现。这两个变量分别保存数组的最大元素和第二大元素,分别记作max1和max2,最终返回max2。
网上找了几个帖子,发现写的代码都有问题,没有考虑到数组最开始两个或多个元素重复的情况。除非数组所有元素都是同一个值,否则需要确保在遍历数组时,max1必须大于max2。
如果数组最开始的几个元素都相等,则需要先找到第一个两相邻元素不相等的数组下标,然后从这个下标开始再往后遍历,根据具体的元素值选择性地更新max1和(或)max2。
还要注意,如果数组某个元素的值大于max1,则需要在更新max1之前,必须先把max1现有的值赋予max2,再将max1自己更新。如果元素值介于max1和max2之间,只更新max2即可。
以下贴出正确代码实现:
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* 求数组第二大元素
*/
public class GetSecondaryMaxValue {
public static void main(String[] args) {
int[] arr1 = {3, 4, 2, 5, 7, 6}; // 6
int[] arr2 = {2, 9, 10, 9, 4, 1, 5}; // 9
int[] arr3 = {5, 5, 5, 3, 3}; // 3
int[] arr4 = {3, 3, 2, 3}; // 2
int[] arr5 = {8, 8, 9, 9, 9}; // 8
int[] arr6 = {5, 6, 6}; // 5
int[] arr7 = {0, 1, 2, 3, 4, 5}; // 4
int[] arr8 = {8, 7, 6, 5, 4, 3, 2, 1}; // 7
// 以上测试用例全部通过
System.out.println(getSecondMaxElement(arr1));
System.out.println(getSecondMaxElement(arr2));
System.out.println(getSecondMaxElement(arr3));
System.out.println(getSecondMaxElement(arr4));
System.out.println(getSecondMaxElement(arr5));
System.out.println(getSecondMaxElement(arr6));
System.out.println(getSecondMaxElement(arr7));
System.out.println(getSecondMaxElement(arr8));
// 用对数器验证
boolean success = true;
for (int i = 0; i < 1000000; i++) {
int length = 3 + (int)(10 * Math.random());
int[] arr = generateRandomArray(length);
int result = getSecondMaxElement(arr);
int result0 = getSecondMaxElement0(arr);
if (result0 != result) {
success = false;
break;
}
}
System.out.println(success ? "OK" : "Failed!"); // OK
}
/**
* 主方法
*/
private static int getSecondMaxElement(int[] arr) {
if (arr == null || arr.length < 2) {
throw new IllegalArgumentException();
}
// max1:最大元素
// max2:第二大元素
int max1 = Math.max(arr[0], arr[1]), max2 = Math.min(arr[0], arr[1]);
int from = 2;
while (max2 == max1 && from < arr.length) {
// 找出第一个max1与max2不相等的位置from
max1 = Math.max(arr[from - 1], arr[from]);
max2 = Math.min(arr[from - 1], arr[from]);
from++;
}
for (int i = from - 1; i < arr.length; i++) {
if (arr[i] > max2 && arr[i] < max1) {
max2 = arr[i];
} else if (arr[i] > max1) {
max2 = max1;
max1 = arr[i];
}
}
return max2;
}
/**
* 对照方法
*/
private static int getSecondMaxElement0(int[] arr) {
Set<Integer> set = new HashSet<>(arr.length);
for (int a : arr) {
set.add(a);
}
int[] dest = new int[set.size()];
int k = 0;
for (int a : set) {
dest[k++] = a;
}
Arrays.sort(dest);
return (dest.length < 2) ? dest[0] : dest[dest.length - 2];
}
/**
* 生成随机数组
*/
private static int[] generateRandomArray(int length) {
if (length < 0) {
throw new IllegalArgumentException();
}
int[] arr = new int[length];
for (int i = 0; i < length; i++) {
arr[i] = (int) (100 * Math.random());
}
return arr;
}
}