一、题目描述
小R正在研究一组观光景点,每个景点都有一个评分,保存在数组 values 中,其中 values[i] 表示第 i 个观光景点的评分。同时,景点之间的距离由它们的下标差 j - i 表示。
一对景点 (i < j) 的观光组合得分为 values[i] + values[j] + i - j,也就是两者评分之和减去它们之间的距离。
小R想知道,在哪种情况下能够获得观光景点组合的最高得分。
二、测试样例
样例1:
输入:
values = [8, 3, 5, 5, 6]
输出:11
样例2:
输入:
values = [10, 4, 8, 7]
输出:16
样例3:
输入:
values = [1, 2, 3, 4, 5]
输出:8
三、思路解析
3.1 暴力求解
遍历所有可能的组合,取最大值,时间复杂度N2
3.2 动态规划
标签是动态规划,肯定要用到动态规划
分别使用两个和values相同大小的一维数组 int[] dpLeft 和 int[] dpRight 来存储指定位置前面最大的值和后面最小的值
举例来说,dpLeft[5], 表示数组values[5]前6个数中(含values[5]), 可以利用的最大的值(该值已经经过了距离衰减的计算)
dpRight[5],表示数组values[5]后面所有的数中(不含values[5]), 可以利用的最大的值(该值已经经过了距离衰减的计算)
需要注意的是,两个dp数组哪个含当前下标不是固定的,只要保证一个含,另一个不含即可
3.2.1 数组的初始化
左dp数组的左边界的第一个元素直接设置成 values数组的左边界, 右dp数组的右边界设置成0
3.2.2 特殊情况
当数组元素个数小于等于1的时候,直接返回0,因为找不出来一对组合
3.2.3 递推公式
记录右边的衰减最大值,没往右走一步,就衰减1,将衰减之后的值和当前的values[i]进行对比,取最大值, 并将衰减最大值再更新成最大值。
for (int i = 1; i < values.length; i++) {
dpLeft[i] = Math.max(values[i], dplTmep-1);
dplTmep = dpLeft[i];
}
3.2.4 最后遍历
最后构造完dp数组之后,只需要从头开始进行遍历,持续搜索 Max(dpRight[i] + dpLeft[i]),返回最后的结果即可
四、最终代码
import java.util.Arrays;
public class Main {
public static int solution(int[] values) {
if(values.length <= 1){
return 0;
}
// write code here
int[] dpLeft = new int[values.length];
dpLeft[0] = values[0];
int dplTmep = dpLeft[0];
int[] dpRight = new int[values.length];
int dprTmep = Integer.MIN_VALUE+1;
for (int i = 1; i < values.length; i++) {
dpLeft[i] = Math.max(values[i], dplTmep-1);
dplTmep = dpLeft[i];
}
dpRight[values.length-1] = 0;
for (int i = dpRight.length - 2; i >= 0; i--) {
dpRight[i] = Math.max(dprTmep-1, values[i+1]-1);
dprTmep = dpRight[i];
}
int re = 0;
for (int i = 0; i < dpRight.length; i++) {
re = Math.max(re, dpLeft[i]+dpRight[i]);
}
return re; // Placeholder return
}
public static void main(String[] args) {
System.out.println(solution(new int[]{8, 3, 5, 5, 6}) == 11 ? 1 : 0);
System.out.println(solution(new int[]{10, 4, 8, 7}) == 16 ? 1 : 0);
System.out.println(solution(new int[]{1, 2, 3, 4, 5}) == 8 ? 1 : 0);
}
}