【LeetCode 1014】最佳观光对 Best Sightseeing Pair

LeetCode 1014题,属于数组类型的题目,题意:
【LeetCode 1014】最佳观光对 Best Sightseeing Pair_第1张图片
翻译成中文,就是要找数组中的两个点,满足:

  • A[i] + A[j] + i - j的值最大
  • i < j

【LeetCode 1014】最佳观光对 Best Sightseeing Pair_第2张图片
【LeetCode 1014】最佳观光对 Best Sightseeing Pair_第3张图片
思路:
最快速的想法,就是直接暴力求解:
因为实际上就是求符合题意的两个点能获得的最大值,直接两个循环:

    public int maxScoreSightseeingPair(int[] A) {
        if (A == null || A.length == 0) return 0;
        int max = 0;
        for (int i = 0; i < A.length; i++) {
            for (int j = i + 1; j < A.length; j++) {
                if (A[i] + A[j] + i - j > max) {
                    max = A[i] + A[j] + i - j;
                }
            }
        }
        return max;
    }

但直接暴力解复杂度 O(n²),LeetCode直接超时了,所以我们要变换思路:
我们观察:A[i] + A[j] + i - j,可以拆分为:A[i] + iA[j] - j,所以,题目相当于,找出一个点 i,且在改点之后,有一个点 j,使得A[i] + iA[j] - j的和获得最大值。
我们可以想到,先遍历一遍数组,记录在当前 i可以获得的A[i] + i的最大值temp[],再第二次遍历数组,看在哪个点,可以获得temp[i[ + A[i] - i的最大值,代码:

    public int maxScoreSightseeingPair(int[] A) {
        if (A == null || A.length == 0) return 0;
        // 用于记录每个点之前,能获取的 A[i] + i的最大值
        int[] temp = new int[A.length];
        int max = Integer.MIN_VALUE;
        // 第一次遍历,用于更新 temp[]
        for (int i = 0; i < A.length - 1; i++) {
            if (A[i] + i > temp[i]) {
                // 若当前 i点的组合大于原始组合,则更新
                temp[i + 1] = A[i] + i;
            } else {
            	// 当前 i点组合未能获得更大的组合值
                temp[i + 1] = temp[i];
            }
        }
        // 第二次遍历
        for (int i = 0; i < A.length; i++) {
            if (temp[i] + A[i] - i > max) {
                max = temp[i] + A[i] - i;
            }
        }
        return max;
    }

该解法的时间复杂度为 O(n),空间复杂度为 O(n)。但该解法遍历了两次数组,而且还有空间开销,那我们可不可以只遍历一次且常数级别的空间开销呢?
其实我们发现:上面的 temp[]用于记录在这个点之前能获取的 A[i] + i组合的最大值,其实我们可以用一个变量进行记录即可,因此,修改代码,有:

    public int maxScoreSightseeingPair(int[] A) {
        if (A == null || A.length == 0) return 0;
        int i = 0, max = Integer.MIN_VALUE;
        for (int j = 1; j < A.length; j++) {
            if (A[i] + A[j] + i - j > max) {
                max = A[i] + A[j] + i - j;
            }
            // 更新 A[i] + i组合能获得最大值的下标
            if (i + A[i] < j + A[j]) {
                i = j;
            }
        }
        return max;
    }

时间复杂度 O(n),空间复杂度 O(1)
提交结果:
【LeetCode 1014】最佳观光对 Best Sightseeing Pair_第4张图片

其他 LeetCode JAVA代码:
https://github.com/Parallelline1996/LeetCode/tree/master

你可能感兴趣的:(算法,LeetCode)