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. 总结

  • 本题核心是判断每个位置能否到达全局最大值
  • 关键依据:如果左边有更大的数,且能"打通"到右侧,就能取全局最大。
  • 从右往左遍历 + 维护最小/最大值,是本题最优思路。
  • 递归版本易于理解,迭代优化版本效率更高。
相关推荐
都市放羊5 分钟前
网络小白自学网工——因特网与网络互联技术
网络·笔记·自学
東隅已逝,桑榆非晚10 分钟前
新手入门指南:认识 C 语言文件操作(上)
c语言·开发语言·笔记
暴躁小师兄数据学院14 分钟前
【AI大数据工程师特训笔记】第08讲:集合运算与超级函数
大数据·笔记·sql·ai·postgresql
BD4SXV17 分钟前
线性二次调节器(Linear Quadratic Regulator,LQR)的无限时域最优控制求解与黎卡提方程
算法·自动化
ST——Jess25 分钟前
2026年度传统文化数字化与命理科技(Ethno-tech)行业趋势研究报告:专业级数智工作台的技术壁垒与评测标准
人工智能·科技·算法·架构
searchforAI32 分钟前
我的Obsidian知识库,现在可以自动剪藏笔记到本地了
人工智能·笔记·学习·音视频·ai工具·obsidian·视频总结
Matrix_111 小时前
第13篇:非线性位移场——漩涡、鱼眼、水波纹与球面化
图像处理·算法
金牌归来发现妻女流落街头1 小时前
【LeetCode 第207题】
算法·leetcode·拓扑·领接表
熬夜敲代码的猫1 小时前
AVL树(C++详解版)
数据结构·c++·算法
lcj25111 小时前
vector的基本使用 + 手搓成员变量 size capacity begin end operator[] reserve扩容 拷贝构造 赋值析构
开发语言·c++·笔记·面试