以记忆化的功能递归方式实现迭代解决方案

时间:2021-03-25 10:34:03

标签: algorithm recursion data-structures stack iteration

我正在尝试解决 leetcode 上的以下问题:Coin Change 2

输入:金额 = 5,硬币 = [1, 2,5] 输出:4 说明:金额有四种补足方式:

5=5

5=2+2+1

5=2+1+1+1

5=1+1+1+1+1

我正在尝试实现一个迭代解决方案,该解决方案基本上使用堆栈模拟/模仿递归。我已设法实施它并且解决方案有效,但它超出了时间限制。

我注意到递归解决方案利用记忆进行优化。我也想将它合并到我的迭代解决方案中,但我不知道如何进行。

我目前的解决方案:

# stack to simulate recursion
stack = []
# add starting indexes and sum to stack
#Tuple(x,y) where x is sum, y is index of the coins array input
for i in range(0, len(coins)):
    if coins[i]<=amount:
        stack.append((coins[i], i))

result = 0
while len(stack)!=0:
    c = stack.pop()
    currentsum = c[0]
    currentindex = c[1]
    # can't explore further
    if currentsum >amount:
        continue
    # condition met, increment result
    if currentsum == amount:
        result = result+1
        continue
    # add coin at current index to sum if doesn't exceed amount (append call to stack)
    if (currentsum+coins[currentindex])<=amount:
        stack.append((currentsum+coins[currentindex], currentindex))
    #skip coin at current index (append call to stack)
    if (currentindex+1)<=len(coins)-1:
        stack.append((currentsum, currentindex+1))

return result

我尝试使用字典来记录附加到堆栈,如下所示:

#if the call has not already happened, add to dictionary
if dictionary.get((currentsum, currentindex+1), None) == None:
   stack.append((currentsum, currentindex+1))
   dictionary[currentsum, currentindex+1)] = 'visited'

例如,如果调用 (2,1) of sum = 2 和 coin-array-index = 1,我会将其附加到字典中。如果再次遇到相同的调用,我不会再次追加它。但是,它不起作用,因为不同的组合可以具有相同的总和和索引。

无论如何我可以在上面的迭代解决方案中加入记忆。我想以一种与递归解决方案在功能上相同的方式来实现。

1 个答案:

答案 0 :(得分:0)

我已经设法找出解决方案。本质上,我使用了后序遍历,并使用了一个状态变量来记录当前调用所处的递归阶段。使用该阶段,我设法在自上而下后自下而上。

我想出的解决方案如下:

def change(self, amount: int, coins: List[int]) -> int:
    if amount<=0:
        return 1
    if len(coins) == 0:
        return 0  
    d= dict()
    #currentsum, index, instruction
    coins.sort(reverse=True)
    stack = [(0, 0, 'ENTER')]
    calls = 0
    while len(stack)!=0:
        currentsum, index, instruction = stack.pop()
        if currentsum == amount:
            d[(currentsum, index)] = 1
            continue
        elif instruction == 'ENTER':
            stack.append((currentsum, index, 'EXIT'))
            
            if (index+1)<=(len(coins)-1):
                if d.get((currentsum, index+1), None) == None:
                    stack.append((currentsum, index+1, 'ENTER'))
            
            newsum = currentsum + coins[index]
            if newsum<=amount:
                if d.get((newsum, index), None) == None:
                    stack.append((newsum, index, 'ENTER'))
        elif instruction == 'EXIT':
            newsum = currentsum + coins[index]
            left = 0 if d.get((newsum, index), None) == None else d.get((newsum, index))
            right = 0 if d.get((currentsum, index+1), None) == None else d.get((currentsum, index+1))
            d[(currentsum, index)] = left+right
        calls = calls+1
    print(calls)
    return d[(0,0)]
相关问题