每日打卡:最佳观光组合

打卡: 最佳观光组合

心情

听钢琴曲写代码真的很舒服。今日钢琴曲《柔如彩虹》——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)取到最大值。

我仿佛听到了智商破碎的声音。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值