LeetCode 每日一题笔记 日期:2026.05.07 题目:3660. 找到所有可以到达的最大值

LeetCode 每日一题笔记

0. 前言

  • 日期:2026.05.07
  • 题目:3660. 找到所有可以到达的最大值
  • 难度:中等
  • 标签:数组、贪心、前缀最值、递归

1. 题目理解

问题描述

给定一个整数数组 nums。对于数组中的每一个位置 i,你可以按照下面的规则跳跃任意次数:

  • 向右跳:只能跳到比当前数的数
  • 向左跳:只能跳到比当前数的数

请你返回一个数组 ans,其中 ans[i] 表示从位置 i 出发,能够到达的最大数值

示例

输入:nums = 2,1,3

输出:2,2,3

2. 解题思路

核心观察

  1. 每个位置能到达的最大值,取决于左边的最大值是否能"打通"到更全局的最大值。
  2. 一旦左边出现比右侧最小值更大的数,就可以到达全局最大值
  3. 可以用前缀最大值快速记录每个位置左侧的最大值及其下标。
  4. 递归思路:从右向左分割区间,用最大值把数组分成两段,分别赋值答案。

算法步骤

原版递归思路

  1. 预处理前缀最大值数组,记录每个位置的最大值及其下标。
  2. 从右往左递归处理:
    • 找到当前区间的最大值位置
    • 如果该最大值 > 右侧最小值,说明能到达全局最大值
    • 给区间内所有位置赋值当前最大值
    • 继续递归处理左半区间

优化版思路

  1. 先求一遍前缀最大值。
  2. 从右往左遍历,维护当前最小值 mn 和当前可达最大值 mx
  3. 如果前缀最大值 > 当前最小值,说明能到达全局最大值,直接赋值。
  4. 否则更新最大值和最小值。

3. 代码实现

原版代码(递归 + 前缀最值)

java 复制代码
package lc3660;

class Solution {
    public void erFen(int[] nums, int right, int[] res, int[][] prevmax, int min, int max) {
        if (right <= 0) {
            return;
        }
        int nowMax = prevmax[right - 1][0];
        int nowMaxLoc = prevmax[right - 1][1];
        if (nowMax > min) {
            nowMax = max;
        }
        for (int i = nowMaxLoc; i < right; i++) {
            if (nums[i] < min) {
                min = nums[i];
            }
            res[i] = nowMax;
        }
        right = nowMaxLoc;
        erFen(nums, right, res, prevmax, min, max);
    }

    public int[] maxValue(int[] nums) {
        int[] res = new int[nums.length];
        int[][] prevMax = new int[nums.length][2];
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > max) {
                max = nums[i];
                prevMax[i][0] = max;
                prevMax[i][1] = i;
            } else {
                prevMax[i][0] = prevMax[i - 1][0];
                prevMax[i][1] = prevMax[i - 1][1];
            }
        }
        erFen(nums, nums.length, res, prevMax, Integer.MAX_VALUE, prevMax[nums.length - 1][0]);
        return res;
    }
}

优化版代码

java 复制代码
class Solution {
public int[] maxValue(int[] nums) {
int n = nums.length;
int[] sum = new int[n];
sum[0] = nums[0];
for(int i = 1; i < n; i++){
sum[i] = Math.max(sum[i - 1], nums[i]);
}
int mn = nums[n - 1];
int mx = sum[n - 1];
for(int j = n - 1; j >= 0; j--){
if(sum[j] > mn){
sum[j] = mx;
}
else{
mx = sum[j];
}
mn = Math.min(mn, nums[j]);
}
return sum;
}
}

4. 代码优化说明

  • 原版使用递归 + 前缀最大值数组,思路直观,通过分段赋值得到答案。
  • 优化版使用一次前缀最大值 + 一次反向遍历,去掉递归,时间、空间更优。
  • 优化版不再需要二维数组,仅用一个数组即可完成计算,代码更简洁。

5. 复杂度分析

原版代码

  • 时间复杂度:O(n)O(n)O(n) ~ O(n2)O(n^2)O(n2) (取决于递归分割次数)
  • 空间复杂度:O(n)O(n)O(n) (前缀数组 + 递归栈)

优化版代码

  • 时间复杂度:O(n)O(n)O(n)
  • 空间复杂度:O(n)O(n)O(n) (仅使用结果数组)

6. 总结

  • 本题核心是判断每个位置能否到达全局最大值
  • 关键依据:如果左边有更大的数,且能"打通"到右侧,就能取全局最大。
  • 从右往左遍历 + 维护最小/最大值,是本题最优思路。
  • 递归版本易于理解,迭代优化版本效率更高。
相关推荐
JieE21215 小时前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
Jack201 天前
HarmonyOS开发中错误处理策略:网络异常统一处理
算法
小小杨树1 天前
读懂色彩:拍照调色不再难
算法·计算机视觉·配色
JieE2122 天前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE2122 天前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
vivo互联网技术2 天前
CVPR 2026 | 全新强化学习框架 BeautyGRPO:重塑真实人像
算法·大模型·cvpr·影像
Darling噜啦啦2 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
用户497863050732 天前
(一)小红的数组操作
算法·编程语言
怕浪猫2 天前
Electron 系列文章封面图
算法·架构·前端框架