为什么在我的 Lua 代码中从上到下和从下到上的效果不同?

我编写了一个动态程序代码,它是关于在三种方式中寻找最小计算数的:除以 3,除以 2,或从给定的数字减去 1 使其变为 1。

首先,我使用自顶向下方式编写了一个名为 'one' 的函数。但是当我将 1,000,000 放入其中时,结果是栈溢出。

其次,我使用自底向上方式编写了一个名为 'two' 的函数。它可与输入的 1,000,000 很好地配合使用。

local num = io.read("*n")

local memo = {
    [0] = 0,
    [1] = 0
}

function one(n)
    if memo[n] == nil then
        if n % 3 == 0 then
            memo[n] = 1 + math.min(one(n-1), one(n//3))
        elseif n % 2 == 0 then
            memo[n] = 1 + math.min(one(n-1), one(n//2))
        else
            memo[n] = 1 + one(n-1)
        end
    end
    return memo[n]
end

local last = 1

function two(n)
    if memo[n] == nil then
        for i = last + 1, n do
            if i % 3 == 0 then
                memo[i] = 1 + math.min(two(i-1), two(i//3))
            elseif i % 2 == 0 then
                memo[i] = 1 + math.min(two(i-1), two(i//2))
            else
                memo[i] = 1 + two(i-1)
            end
        end
        last = n
    end
    return memo[n]
end

print(two(num))

我不知道为什么会发生这种情况。难道它的工作方式不是相似的吗?

点赞
用户7396148
用户7396148

以下是中文翻译,并保留原始的 markdown 格式:

由于没有定义较低的数字,因此您从上到下得到了栈溢出。

让我们通过两个函数,如果我们提供输入为 5,我将在代码中添加打印行以帮助说明代码的运行方式。


我将从函数二开始。

Undefined: 5 -- 这是第一次调用。
Undefined: 2 -- 在 for 循环中首次出现的值。
%2: 2        -- 进入 mod 2 块。
Defined: 1   -- 第二次调用。 (现在深入了 2 次)
Defined: 1   -- 第三次调用。 (仍深入 2 次)
Undefined: 3 -- First calls for loop 的下一个值。(回到 1 层)
%3: 3        -- 进入 mod 3 块。
Defined: 2   -- 第四次调用。 (现在深入了 2 次)
Defined: 1   -- 第五次调用。 (仍深入 2 次)
Undefined: 4 -- First calls for loop 的下一个值。(回到 1 层)
%2: 4        -- 进入 mod 4 块。
Defined: 3   -- 第六次调用。 (现在深入了 2 次)
Defined: 2   -- 第七次调用。 (仍深入 2 次)
Undefined: 5 -- First calls for loop 的下一个值。(回到 1 层)
else: 5      -- 进入 else 块。
Defined: 4   -- 第八次调用。 (仍深入 2 次)
3            -- 从初始调用返回。

正如您所看到的,循环的每次迭代都有先前已定义的值,因此它们立即返回,并且实际上不会递归超过 2 层。


以下是函数一的输出:

Undefined: 5 -- 这是第一次调用。
else: 5      -- 进入 else 块。
Undefined: 4 -- 第二次调用。 (现在深入了 2 次)
%2: 4        -- 进入 mod 2 块。
Undefined: 3 -- 第三次调用。 (现在深入了 3 层)
%3: 3        -- 进入 mod 3 块。
Undefined: 2 -- 第四次调用。 (现在深入了 4 层)
%2: 2        -- 进入 mod 2 块。
Defined: 1   -- 第五次调用。 (现在深入了 5 层)
Defined: 1   -- 第六次调用。 (仍在 5 层)
Defined: 1   -- 第七次调用。 (值为 3 的第二次调用)
Defined: 2   -- 第八次调用。 (值为 4 的第二次调用)
3            -- 从初始调用返回。

由于没有定义较低的值,每个调用都必须越来越深,这导致了堆栈溢出。

函数二实际上并不像函数一那样递归,您只能对 memo[i-1]memo[i/2] 进行处理,因为它们已被保证已经处理过。

2019-06-10 18:52:42