求数组的第二大元素

题目描述:

给定数组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;
    }

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值