递归和动态编程的不同结果

时间:2017-01-11 05:49:27

标签: python algorithm python-2.7

处理以下问题,

问题

给定m * n网格,允许一个向上或向右移动,找到两个网格点之间的不同路径。

我写了一个递归版本和一个动态编程版本,但是它们会返回不同的结果,并且有什么想法会出错?

源代码

from collections import defaultdict
def move_up_right(remaining_right, remaining_up, prefix, result):
    if remaining_up == 0 and remaining_right == 0:
        result.append(''.join(prefix[:]))
        return
    if remaining_right > 0:
        prefix.append('r')
        move_up_right(remaining_right-1, remaining_up, prefix, result)
        prefix.pop(-1)
    if remaining_up > 0:
        prefix.append('u')
        move_up_right(remaining_right, remaining_up-1, prefix, result)
        prefix.pop(-1)
def move_up_right_v2(remaining_right, remaining_up):
    # key is a tuple (given remaining_right, given remaining_up),
    # value is solutions in terms of list
    dp = defaultdict(list)
    dp[(0,1)].append('u')
    dp[(1,0)].append('r')
    for right in range(1, remaining_right+1):
        for up in range(1, remaining_up+1):
            for s in dp[(right-1,up)]:
                dp[(right,up)].append(s+'r')
            for s in dp[(right,up-1)]:
                dp[(right,up)].append(s+'u')
    return dp[(right, up)]

if __name__ == "__main__":
    result = []
    move_up_right(2,3,[],result)
    print result
    print '============'
    print move_up_right_v2(2,3)

2 个答案:

答案 0 :(得分:2)

动态编程版本的问题在于它没有考虑从多个向上移动('uu...')或多个向右移动('rr...')开始的路径。

在执行主循环之前,您需要为来自dp[(x,0)]x1的每个remaining_right+1填写dp[(0,y)]来自y 1remaining_up+1

换句话说,替换它:

dp[(0,1)].append('u')
dp[(1,0)].append('r')

用这个:

for right in range(1, remaining_right+1):
    dp[(right,0)].append('r'*right)
for up in range(1, remaining_up+1):
    dp[(0,up)].append('u'*up)

答案 1 :(得分:2)

在版本2中,您应该从0开始for循环而不是1.从1开始,您将缺少可能首先遍历底行或最左列的排列。

将版本2更改为:

def move_up_right_v2(remaining_right, remaining_up):
    # key is a tuple (given remaining_right, given remaining_up),
    # value is solutions in terms of list
    dp = defaultdict(list)
    dp[(0,1)].append('u')
    dp[(1,0)].append('r')
    for right in range(0, remaining_right+1):
        for up in range(0, remaining_up+1):
            for s in dp[(right-1,up)]:
                dp[(right,up)].append(s+'r')
            for s in dp[(right,up-1)]:
                dp[(right,up)].append(s+'u')
    return dp[(right, up)]  

然后:

result = []
move_up_right(2,3,[],result)

set(move_up_right_v2(2,3)) == set(result)
True

只是为了好玩......另一种方式:

from itertools import permutations

list(map(''.join, set(permutations('r'*2+'u'*3, 5))))