【LeetCode闲暇一题】1014. 最佳观光组合

13 篇文章 0 订阅
8 篇文章 0 订阅
题目:

给定正整数数组 A,A[i] 表示第 i 个观光景点的评分,并且两个景点 i 和 j 之间的距离为 j - i。
一对景点(i < j)组成的观光组合的得分为(A[i] + A[j] + i - j):景点的评分之和减去它们两者之间的距离。
返回一对观光景点能取得的最高分。
示例:
输入:[8,1,5,2,6]
输出:11
解释:i = 0, j = 2, A[i] + A[j] + i - j = 8 + 5 + 0 - 2 = 11
提示:
2 <= A.length <= 50000
1 <= A[i] <= 1000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-sightseeing-pair
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

我的思路:

遍历出所有的组合,获得得分最大的组合,且因为是两个景点,所以不会有 1-1, 2-2的组合。同时1-2,2-1的组合是同一个组合,所以外层循环从0开始,循环到A.length-1即可,i-j即为距离,所以内层循环以距离为标准,从1开始,截止到A.length-i.记录最大的得分,最后返回。

我的代码:
class Solution {
    public int maxScoreSightseeingPair(int[] A) {
    	// 默认得分为0
        int maxScore = 0;
        for(int i = 0; i < A.length-1; i++) {
        	// j代表i与下一个景点的距离
           for(int j = 1; j < A.length-i; j++) {
           	   // 两个景点的得分减去距离
               maxScore = Math.max(maxScore, A[i] + A[i+j] - j);
            } 
        }
        return maxScore;
    }
}

运行结果:
在这里插入图片描述
超时… 接着我去查看了题解:

官方题解:

方法一:枚举 思路和算法

我们考虑从前往后枚举 j j j 来统计答案,对于每个观光景点 j j j 而言,我们需要遍历 [ 0 , j − 1 ] [0,j-1] [0,j1]的观光景点 i i i 来计算组成观光组合 ( i , j ) (i,j) (i,j)得分的最大值 c n t j {cnt}_j cntj ​ 来作为第 j j j个观光景点的值,那么最后的答案无疑就是所有观光景点值的最大值,即 m a x j = 0.. n − 1 { c n t j } max_{j=0..n-1}\{cnt_j\} maxj=0..n1{cntj}。但是枚举 j j j 需要 O ( n ) O(n) O(n) 的时间复杂度,遍历 [ 0 , j − 1 ] [0,j-1] [0,j1]的观光景点 i i i 也需要 O ( n ) O(n) O(n) 的时间复杂度,因此该方法总复杂度为 O ( n 2 ) O(n^2) O(n2) ,不能通过所有测试用例,我们需要进一步优化时间复杂度。

我们回过头来看得分公式,我们可以将其拆分成 A [ i ] + i A[i]+i A[i]+i A [ j ] − j A[j]-j A[j]j 两部分,这样对于统计景点 j j j答案的时候,由于 A [ j ] − j A[j]-j A[j]j 是固定不变的,因此最大化 A [ i ] + i + A [ j ] − j A[i]+i+A[j]-j A[i]+i+A[j]j的值其实就等价于求 [ 0 , j − 1 ] [0,j-1] [0,j1] A [ i ] + i A[i]+i A[i]+i 的最大值 m x mx mx,景点 j j j 的答案即为 m x + A [ j ] − j mx+A[j]-j mx+A[j]j 。而 m x mx mx 的值我们只要从前往后枚举 j j j 的时候同时维护即可,这样每次枚举景点 j j j的时候,寻找使得得分最大的 i i i 就能从 O ( n ) O(n) O(n) 降至 O ( 1 ) O(1) O(1) 的时间复杂度,总时间复杂度就能从 O ( n 2 ) O(n^2) O(n2) 降至 O ( n ) O(n) O(n)

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/best-sightseeing-pair/solution/zui-jia-guan-guang-zu-he-by-leetcode-solution/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

根据题解,我们发现解题的关键在于 A [ i ] + A [ j ] + i − j A[i] + A[j] + i - j A[i]+A[j]+ij这个算式上面,其可以分为 A [ i ] + i A[i] + i A[i]+i A [ j ] − j A[j] - j A[j]j两部分,我们只需在遍历过程中记录遍历过的一部分的最大值(即当得分最大时,这两部分肯定为非相同景点下对应的最大值),再拿这个最大值与当前遍历节点得分相加即可得到相对较大的得分,再与已记录的最大得分比较,取最大的。遍历结束时即可得到最大得分,根据这个思路,可以得到如下接答。

官方思路下的个人解题:
class Solution {
    public int maxScoreSightseeingPair(int[] A) {
        int left = A[0] + 0;
        int maxScope = 0;
        for(int i = 1; i < A.length; i++) {
        	// 算出当前节点与之前节点最大值的和得出相对最大值
            maxScope = Math.max(maxScope, left + A[i] - i);
            // 记录遍历过的最大得分
            left = Math.max(left, A[i] + i);
        }
        return maxScope;
    }
}

运行结果:
在这里插入图片描述

官方题解下的其它联想:

因为在题解中我们可以看到我们实际求的是 A [ i ] + i A[i] + i A[i]+i A [ j ] − j A[j] - j A[j]j两部分的相应最大值,我们可以记录 A [ i ] + i A[i] + i A[i]+i的最大值,自然也可以记录 A [ j ] − j A[j] - j A[j]j的最大值,然后遍历 A [ i ] + i A[i] + i A[i]+i。但是这样我们需要从后往前遍历,记录 A [ j ] − j A[j] - j A[j]j,然后遍历最大值。不能从前遍历。因为如果从前遍历就变为 A [ i ] − i + A [ j ] + j A[i] - i + A[j] + j A[i]i+A[j]+j,计算总得分的方式就变为得分之和+加上两者之间的距离了,违背了题意。
从后往前遍历下的解答方式:

class Solution {
    public int maxScoreSightseeingPair(int[] A) {
    	// 最右边的值
        int right = A[A.length-1] - A.length + 1;
        int maxScope = 0;
        // 从右边第二个开始往前遍历
        for(int i = A.length-2; i >= 0 ; i--) {
            maxScope = Math.max(maxScope, right + A[i] + i);
            right = Math.max(right, A[i] - i);
        }
        return maxScope;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yue_hu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值