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

LeetCode 2623. Memoize代码测试用例报错,求错误原因排查

解决LeetCode 2623. Memoize时遇到的问题

题目要求

给定一个函数fn,返回它的记忆化版本。记忆化函数不会对相同的输入调用两次,而是返回缓存的值。可输入的函数有三种:

  • sum:接收两个整数a和b,返回a+b;
  • fib:接收单个整数n,n<=1时返回1,否则返回fib(n-1)+fib(n-2);
  • factorial:接收单个整数n,n<=1时返回1,否则返回factorial(n-1)*n。

我的JavaScript实现

/**
 * @param {Function} fn
 * @return {Function}
 */
function memoize(fn) {
    let arr = [];
    let result = [];
    return function (...args) {
        if (!(arr.toString().match(args.toString()))) {
            arr.push(args);
            let val = fn(...args);
            result.push(val);
            return val;
        } else {
            for (let i = 0; i < arr.length; i++) {
                if (arr[i].toString() === args.toString()) {
                    return result[i];
                }
            }
        }
    }
}

/** 
 * LeetCode提供的示例:
 * let callCount = 0;
 * const memoizedFn = memoize(function (a, b) {
 *   callCount += 1;
 *   return a + b;
 * })
 * memoizedFn(2, 3) // 5
 * memoizedFn(2, 3) // 5
 * console.log(callCount) // 1 
 */

失败的测试用例

let callCount = 0;
const memoizedFn = memoize(function (a, b) {
   callCount += 1;
   return a + b;
})
memoizedFn(122, 931)
memoizedFn(34, 216)
memoizedFn(22, 9)
memoizedFn(1, 803)
callCount // 预期为4,但我的代码返回3

问题分析与修复

错误根源

问题出在判断参数是否已缓存的逻辑上:你用arr.toString().match(args.toString())做检查,这是子串匹配而非精确匹配参数组合。

在测试用例的第三次调用memoizedFn(22,9)时,args.toString()是"22,9",此时arr里已有[122,931]和[34,216],arr.toString()的结果是"122,931,34,216"——这个字符串包含子串"22,9"(来自"122,931"中的"22,9"部分),所以match返回匹配结果,代码误判该参数已存在,跳过了fn的调用,导致callCount没有增加。而进入else分支遍历arr时,又找不到完全匹配的参数,函数最终没有返回正确值,但callCount少加了一次。

修复方案

方案1:使用Map缓存(推荐)

用Map存储参数与结果的映射,以参数的序列化字符串作为键,实现精确匹配:

function memoize(fn) {
    const cache = new Map();
    return function(...args) {
        const key = JSON.stringify(args);
        if (cache.has(key)) {
            return cache.get(key);
        }
        const result = fn(...args);
        cache.set(key, result);
        return result;
    }
}

方案2:改进数组存储的匹配逻辑

如果坚持用数组存储,需要逐个检查每个缓存参数的toString是否与当前参数完全相等,而非子串匹配:

function memoize(fn) {
    const argsList = [];
    const results = [];
    return function(...args) {
        const argStr = args.toString();
        // 精确查找是否存在完全匹配的参数
        const index = argsList.findIndex(item => item.toString() === argStr);
        if (index !== -1) {
            return results[index];
        }
        // 无匹配则执行函数并缓存
        const result = fn(...args);
        argsList.push(args);
        results.push(result);
        return result;
    }
}

为什么原逻辑会出错

arr.toString()会把所有缓存的参数数组拼接成一个大字符串,比如[[122,931], [34,216]]会变成"122,931,34,216",此时任何参数组合的toString如果是这个大字符串的子串,都会被误判为已缓存。这种情况在参数包含连续数字时很容易发生,比如(22,9)的toString就会匹配(122,931)的toString的子串。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 22:12:06