1. 题目
给你一个整数数组 nums。
从任意下标 i 出发,你可以根据以下规则跳跃到另一个下标 j:
仅当 nums[j] < nums[i]时,才允许跳跃到下标 j,其中 j > i。 仅当 nums[j] > nums[i]时,才允许跳跃到下标 j,其中 j < i。 对于每个下标 i,找出从 i 出发且可以跳跃 任意 次,能够到达 nums 中的 最大值 是多少。
返回一个数组 ans,其中 ans[i] 是从下标 i 出发可以到达的最大值。
示例 1:
输入: nums = [2,1,3]
输出: [2,2,3]
解释:
对于 i = 0:没有跳跃方案可以获得更大的值。 对于 i = 1:跳到 j = 0,因为 nums[j] = 2 大于 nums[i]。 对于 i = 2:由于 nums[2] = 3 是 nums 中的最大值,没有跳跃方案可以获得更大的值。 因此,ans = [2, 2, 3]。
示例 2:
输入: nums = [2,3,1]
输出: [3,3,3]
解释:
对于 i = 0:向后跳到 j = 2,因为 nums[j] = 1 小于 nums[i] = 2,然后从 i = 2 跳到 j = 1,因为 nums[j] = 3 大于 nums[2]。 对于 i = 1:由于 nums[1] = 3 是 nums 中的最大值,没有跳跃方案可以获得更大的值。 对于 i = 2:跳到 j = 1,因为 nums[j] = 3 大于 nums[2] = 1。 因此,ans = [3, 3, 3]。
提示:
1 <= nums.length <= 10e5 1 <= nums[i] <= 10e9
2. 分析
这道题还是挺有意思的,可以从当前位置跳到比当前值大的左侧位置,也可以跳到比当前值小的右侧位置,且可以多次跳跃。值得注意的是,有些值,就是需要经过多次左右跳跃之后才能够获取到目标最大值的。
我的思路是分别记录当前位置左侧的最大值和右侧的最小值,每次移动都先移动到左侧的最大值处,再移动到右侧最远处的比最大值小的位置,以此循环,直到连续两次移动后还在原位置,则证明到达了可及的最右侧。
按照这个思路实现后,加上了数组记忆功能,但还是没有通过最后几道用例,超出时间限制。主要是我在找跳转到最远处下标时,使用了倒序的循环。
最后加了一层预处理,将每个位置跳转的路线通过批处理给初始化,减少了在遍历中的循环,然后就通过啦。
3. 代码实现
import java.util.Arrays;
class Solution {
public int[] maxValue(int[] nums) {
int len = nums.length;
// 最左侧到当前位置出现的最大值
int[] leftMax = new int[len];
int maxVal = nums[0];
for (int i = 0; i < len; i++) {
leftMax[i] = maxVal = Math.max(maxVal, nums[i]);
}
// 最右侧到当前位置出现的最小值
int[] rightMin = new int[len];
int minVal = nums[len - 1];
for (int i = len - 1; i >= 0; i--) {
rightMin[i] = minVal = Math.min(minVal, nums[i]);
}
// 预处理所有的最佳跳跃方案
int[] jump = new int[len];
int bestJ = len - 1; // 从后往前,一次遍历搞定
for (int i = len - 1; i >= 0; i--) {
int target = leftMax[i];
while (bestJ > i && rightMin[bestJ] >= target) {
bestJ--;
}
jump[i] = Math.max(bestJ, i);
}
// 递归求解
int[] res = new int[len];
int[] resMemory = new int[len];
Arrays.fill(resMemory, 0);
for (int i = 0; i < len; i++) {
res[i] = findMaxValue(leftMax, jump, i, resMemory);
}
return res;
}
public static int findMaxValue(int[] leftMax, int[] jump, int lastFindIndex, int[] resMemory) {
if (resMemory[lastFindIndex] != 0) {
// 缓存中已经有了
return resMemory[lastFindIndex];
}
int nextIdx = jump[lastFindIndex];
if (nextIdx == lastFindIndex) {
return resMemory[lastFindIndex] = leftMax[lastFindIndex];
}
int ans = findMaxValue(leftMax, jump, nextIdx, resMemory);
resMemory[lastFindIndex] = ans;
return ans;
}
}