为什么自上而下和自下而上的工作方式在我的Lua代码中有所不同?

时间:2019-06-10 17:39:55

标签: lua dynamic-programming

我编写了一个动态程序代码。它是关于通过三种方式搜索最小数量的计算:除以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))

我不知道为什么会这样。难道不是同样安静吗?

1 个答案:

答案 0 :(得分:0)

因为没有定义较低的数字,所以从上到下会出现堆栈溢出。

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


我将从第二个功能开始。

Undefined: 5 -- This is the first call.
Undefined: 2  -- first value once in the for loop.
%2: 2         -- Enter mod 2 block.
Defined: 1    -- Second call. (now 2 calls deep)
Defined: 1    -- Third call. (still 2 calls deep)
Undefined: 3  -- Next  value in First calls for loop. (back to 1 deep)
%3: 3         -- Enter mod 3 block.
Defined: 2    -- Forth call. (now  2 calls deep)
Defined: 1    -- Fifth call. (still 2 calls deep)
Undefined: 4  -- Next  value in First calls for loop. (back to 1 deep)
%2: 4         -- Enter mod 4 block.
Defined: 3    -- Sixth call. (now 2 calls deep)
Defined: 2    -- Seventh call. (still 2 calls deep)
Undefined: 5  -- Next  value in First calls for loop. (back to 1 deep)
else: 5       -- Enter else block.
Defined: 4    -- Eighth call. (still 2 calls deep)
3             -- return from initial call.

您可以看到循环的每个迭代都是已定义的先前值,因此它们会立即返回,并且实际上不会执行超过2次调用的递归。


这是函数一的输出:

Undefined: 5 -- This is the first call.
else: 5      -- Enter the else block.
Undefined: 4 -- Second call. (now 2 calls deep)
%2: 4        -- Enter mod 2 block.
Undefined: 3 -- Third call. (now 3 calls deep)
%3: 3        -- Enter mod 3 block.
Undefined: 2 -- Forth call. (now 4 calls deep)
%2: 2        -- Enter mod 2 block.
Defined: 1   -- Fifth call. (now 5 calls deep)
Defined: 1   -- Sixth call. (still 5 calls deep)
Defined: 1   -- Seventh call. (Second call from value 3)
Defined: 2   -- Eighth call. (Second call from value 4)
3            -- return from initial call.

由于未定义任何较低的值,因此每个调用都必须越来越深入。 这导致堆栈溢出。

函数2并不像函数1那样真正地递归,您可以执行memo[i-1]memo[i/2],因为它们被认为已被处理。