心情
听钢琴曲写代码真的很舒服。今日钢琴曲《柔如彩虹》——Richard Clayderman
有必要记录一下今日的沙雕行为:和同事们组团买彩票,执行人全程直播,大家网上围观😂
读题
leetcode: 297. 二叉树的序列化与反序列化
描述:
给定正整数数组 A,A[i] 表示第 i 个观光景点的评分,并且两个景点 i 和 j 之间的距离为 j - i。
一对景点(i < j)组成的观光组合的得分为(A[i] + A[j] + i - j):景点的评分之和减去它们两者之间的距离。
返回一对观光景点能取得的最高分。
测试用例:
输入:[8,1,5,2,6]
输出:11
提示:
2 <= A.length <= 50000
1 <= A[i] <= 1000
乍一看,双层for循环就能解决嘛。当提交等待了10s后,我傻了。
再一看提示,5w条数据的测试用例,25亿次循环……
思路
1:外层循环位置差,从1~2000,也就是两个观光位置的距离
2:内层循环数组
3:实际上,外层循环中,观光位置的距离不能超过2000-内层得出的最大值的。
实现
public int maxScoreSightseeingPair(int[] A) {
int result = 0;
//由提示得到的限制条件,i为两者的距离,i超过2000-result,point必然比result小
for (int i = 1; i <= Math.min(2000-result,A.length - 1); i++) {
for (int j = 0; j + i <= A.length - 1; j++) {
int point = A[j] + A[j+i] - i;
if(point > result){
result = point;
}
}
}
return result;
}
point = A[j] + A[j+i] - i
result = 2000 - i,A[j] + A[j+i]最大为2000
i = 2000-result,若result要尽可能地大,则i要尽可能地小。所以代码中i<=2000-result
提交
执行用时127ms比较多了,其他开发大多是5ms,这~
标答
public int maxScoreSightseeingPair(int[] A) {
int ans = 0, mx = A[0] + 0;
for (int j = 1; j < A.length; ++j) {
ans = Math.max(ans, mx + A[j] - j);
// 边遍历边维护
mx = Math.max(mx, A[j] + j);
}
return ans;
}
官方题解
真就一层循环,这个思路果然厉害。
将 A[i] + A[j] + i - j 拆为:(A[i] + i) + (A[j] - j)
A[i] + i 必然为正数,视为i处位置得分:景点得分+位置距离起点的距离。
A[j] - j 不一定为正数,视为j处得分:景点得分-位置距离起点的距离。
随着j的增大,A[j] - j会越来越小,但是只要A[i] + i足够大就能保证结果为正。
循环中不断地取A[i] + i 的最大值,能够保证(A[i] + i) + (A[j] - j)取到最大值。
我仿佛听到了智商破碎的声音。。。