2020年6月17日 最佳观光组合 maxScoreSightseeingPair
默认格式:
class Solution {
public int maxScoreSightseeingPair(int[] A) {
}
}
解题思路:
没有解题思路之前,暴力算法先解决了一下。
这道题的意思,找到两个点,他们的值相加并且下标相减得到一个数值,计算这个数值的最大值。
public int maxScoreSightseeingPair(int[] A) {
int res=A[0];
for (int i=0;i<A.length;i++){
for (int j=i+1;j<A.length;j++)
{
res=Math.max(res, A[i]+A[j]+i-j);
}
}
return res;
}
果然超出时间限制。所以我们要对其进行优化。
我们找到链各个相邻的点,i和i+1,计算他们到j的值,可以得到下面的关系
A[i]+A[j]+i-j-(A[i+1]+A[j]+i+1-j)=A[i]-A[i+1]-1
如果A[i]-A[i+1]-1>0 ,表示i到j的值比i+1到j的值大,即我们可以得到 A[i]>A[i]+1
我们不难发现一点,如果A[i]的值比A[i+1]的值要小,那么A[i]+A[j]+i-j必定会比A[i+1]+A[j]+i+1-j小,同理
如果A[i]的值比A[i+1]的值要大超过1。
我们可以延伸得到
A[i]>A[i+x]+x则i+x到j的值比i大
在思考的过程中,我想到了一种使用滑动窗口的方式来实现该算法。
刚开始,起点和终点在同一位置,返回值也是0。
然后end后移,寻找能够替代start的存在的坐标,使任意的j>end都能实现A[end]+A[j]+end-j>A[star]+A[j]+start-j
所以找到了下标是1的100,此时记下val197
start右移,找到start-end之见最大的值,直到start到达end
然后将end向右移,直到val大于197,找到下标7的494
此时start再次右移,记下中间得到的最大的值499
此时end继续右移,找到400的替代品
正确性验证。
由于我们规定寻找end比start要大的值,所以end+start的值必定比中间任意两个值得到的结果更大。
因为end+start>2start,而中间的两个值相加得到的必定小于2start。
然后计算start之间到end之间最大的值,得到的值必定小于2end的值的大小。
思路已经有了,下面就是代码了。
但是现在有另外一种思路:
为什么不直接记下对于右边最优的位置,因为我们可以计算出一个位置比其他小于j的所有值都大,然后右边的所有值都只要和最大的比,不需要和前面的每一个值进行对比了。
代码如下
public int maxScoreSightseeingPair(int[] A) {
int ans = 0;
int max = A[0] + 0;
for (int j = 1; j < A.length; ++j) {
ans = Math.max(ans, max + A[j] - j);
max = Math.max(max, A[j] + j);
}
return ans;
}