You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为最长递增子序列(LIS)解法添加缓存后结果错误,请求排查问题

问题分析与修复方案

你的缓存版本出现错误的核心原因是递归状态的定义和缓存key不匹配,而且原递归函数依赖传递的res参数来累积长度,这导致同一prev_i和curr_i的状态下,不同的res值会被错误复用缓存结果。

具体问题拆解

在无缓存的版本中,res是随调用路径传递的累计长度,不同路径到达同一个prev_i和curr_i时,res可能不一样。但你添加缓存时,只把prev_i+1和curr_i+1作为缓存key,完全忽略了res的影响——这就导致后续调用同一prev_i、curr_i时,会直接返回之前存储的、基于另一个res值计算出的结果,最终得到错误的输出。

比如在测试用例[5,4,19,5,7,12]中,当递归到prev_i=2(对应元素19)、curr_i=3(对应元素5)时,原缓存版本会返回当前的res值(此时可能是3),但另一条路径到达这个状态时res值不同,缓存的结果就会干扰正确计算,最终导致输出3而不是预期的4。

修复思路

我们需要重构递归函数,让它的返回值直接表示从prev_i(上一个选中元素的索引)和curr_i(当前遍历位置)开始,能得到的最长递增子序列长度,不再依赖外部传入的res参数。这样,缓存的key(prev_i+1和curr_i+1)就能唯一确定状态,不会受调用路径影响。

修正后的代码

var recur = function(dp, ns, prev_i, curr_i) {
    // 遍历完所有元素,没有更多可选,返回0
    if (curr_i >= ns.length) {
        return 0;
    }
    // 检查缓存,存在则直接返回
    if (prev_i !== -1 && dp[prev_i + 1][curr_i + 1] !== undefined) {
        return dp[prev_i + 1][curr_i + 1];
    }
    
    // 情况1:选择当前元素(满足递增条件时)
    let take = 0;
    if (prev_i === -1 || ns[curr_i] > ns[prev_i]) {
        take = 1 + recur(dp, ns, curr_i, curr_i + 1);
    }
    
    // 情况2:不选择当前元素
    let notTake = recur(dp, ns, prev_i, curr_i + 1);
    
    // 计算当前状态的最大值并缓存
    const maxVal = Math.max(take, notTake);
    if (prev_i !== -1) {
        dp[prev_i + 1][curr_i + 1] = maxVal;
    }
    return maxVal;
};

var lengthOfLIS = function(ns) {
    if (ns.length === 0) return 0;
    if (ns.length === 1) return 1;
    // 初始化dp数组,处理prev_i=-1的情况(转成索引0)
    const dp = Array(ns.length + 1)
        .fill(undefined)
        .map(() => Array(ns.length + 1).fill(undefined));
    // 初始调用:还未选择任何元素(prev_i=-1),从第一个元素开始遍历
    return recur(dp, ns, -1, 0);
};

为什么这样能解决问题?

  • 递归函数的返回值是当前状态下的最长长度,而非依赖外部传递的累积值,每个prev_i和curr_i的状态对应唯一的最长长度,缓存不会再出错。
  • 对于测试用例[5,4,19,5,7,12],修正后的代码会正确计算出最长递增子序列(比如[4,5,7,12])的长度4。

内容的提问来源于stack exchange,提问作者kenpeter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 08:58:10