3205. 最大数组跳跃得分 I 🔒
题目描述
给定一个数组 nums
,你必须从索引 0 开始跳跃,直到到达数组的最后一个元素,使得获取 最大 分数。
每一次 跳跃 中,你可以从下标 i
跳到一个 j > i
的下标,并且可以得到 (j - i) * nums[j]
的分数。
返回你能够取得的最大分数。
示例 1:
输入:nums = [1,5,8]
输出:16
解释:
有两种可能的方法可以到达最后一个元素:
0 -> 1 -> 2
得分为(1 - 0) * 5 + (2 - 1) * 8 = 13
。0 -> 2
得分为(2 - 0) * 8 = 16
。
示例 2:
输入:nums = [4,5,2,8,9,1,3]
输出:42
解释:
我们可以按 0 -> 4 -> 6
进行跳跃,得分为 (4 - 0) * 9 + (6 - 4) * 3 = 42
。
提示:
2 <= nums.length <= 103
1 <= nums[i] <= 105
解法
方法一:记忆化搜索
我们设计一个函数 \(\textit{dfs}(i)\),表示从下标 \(i\) 出发,能够获得的最大分数。那么答案就是 \(\textit{dfs}(0)\)。
函数 \(\textit{dfs}(i)\) 的执行过程如下:
我们枚举下一个跳跃的位置 \(j\),那么从下标 \(i\) 出发,能够获得的分数就是 \((j - i) \times \textit{nums}[j]\),加上从下标 \(j\) 出发,能够获得的最大分数,总分数就是 \((j - i) \times \textit{nums}[j] + \textit{dfs}(j)\)。我们枚举所有的 \(j\),取分数的最大值即可。
为了避免重复计算,我们使用记忆化搜索的方法,将已经计算过的 \(\textit{dfs}(i)\) 的值保存起来,下次直接返回即可。
时间复杂度 \(O(n^2)\),空间复杂度 \(O(n)\)。其中 \(n\) 是数组的长度。
1 2 3 4 5 6 7 8 9 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
方法二:动态规划
我们可以将方法一中的记忆化搜索转换为动态规划。
定义 \(f[j]\) 表示从下标 \(0\) 出发,到下标 \(j\) 结束,能够获得的最大分数。那么答案就是 \(f[n - 1]\)。
状态转移方程为:
时间复杂度 \(O(n^2)\),空间复杂度 \(O(n)\)。其中 \(n\) 是数组的长度。
1 2 3 4 5 6 7 8 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
1 2 3 4 5 6 7 8 9 10 |
|
1 2 3 4 5 6 7 8 9 10 |
|
方法三:单调栈
我们观察发现,对于当前位置 \(i\),我们应该跳到下一个值最大的位置 \(j\),这样才能获得最大的分数。
因此,我们遍历数组 \(\textit{nums}\),维护一个从栈底到栈顶单调递减的栈 \(\textit{stk}\)。对于当前遍历到的位置 \(i\),如果栈顶元素对应的值小于等于 \(\textit{nums}[i]\),我们就不断地弹出栈顶元素,直到栈为空或者栈顶元素对应的值大于 \(\textit{nums}[i]\),然后将 \(i\) 入栈。
然后,我们初始化答案 \(\textit{ans}\) 和当前位置 \(i = 0\),遍历栈中的元素,每次取出栈顶元素 \(j\),更新答案 \(\textit{ans} += \textit{nums}[j] \times (j - i)\),然后更新 \(i = j\)。
最后返回答案 \(\textit{ans}\)。
时间复杂度 \(O(n)\),空间复杂度 \(O(n)\)。其中 \(n\) 是数组的长度。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|