递归基表示

时间:2016-02-27 01:18:52

标签: python python-3.x recursion base

我很高兴在Python中再次学习递归,而基础很容易,似乎有一点我只是失去了递归问题解决的能力。

例如下面的问题。

写一个递归函数库,它有两个参数,n,一个基数为10的正整数,b,一个介于2和9之间的整数。该函数返回数字n的基数b表示。数字的基数b表示使用数字0,..,b-1,数字的位置表示基数的幂。

>>> base(5,3)  # write 5 in base 3
'12'

>>> base(887,7)  # write 887 in base 7
'2405'

我没有使用递归就完成了问题。

def base(n, b):
    if n == 0:
        return [0]
    digits = []
    while n:
        digits.append(int(n % b))
        n //= b
    return digits[::-1]

如果有人愿意通过递归方式解决这个问题,我将不胜感激。

此外,学习在问题出现之后学习递归思考问题的最佳方法是什么?我习惯于立即为我点击新概念,事实上我用递归打了这个砖墙,这对我来说有点担心。

3 个答案:

答案 0 :(得分:2)

递归程序有两个基本部分:

  1. 您必须知道何时停止!

  2. 您必须能够通过解决相同问题的较小版本来解决问题。

  3. 让我们来看看你的“问题”:

      

    您希望生成一个代表基n写的b的字符串。

    一些快速的经验法则:如果问题涉及“整数”,则可能的停止点为零。如果它涉及“字符串”,则可能的停止点是空字符串。如果它涉及像列表这样的复杂数据结构,则可能的停止点是空数据结构。 (这并不总是正确的。但是对于课堂作业来说总是如此。; - )

    无论如何,你已经意识到使用n作为最重要的变量,并将其测试为零。

    我将建议 错误。 (仅仅因为......)

    让我们尝试稍微不同的终止条件:n < b。在这种情况下,您知道可以生成一个数字。

    所以:

    if n < b:
        return str(n)
    

    完成后,我们能做什么?好吧,你的代码的其余部分非常适合:

    def base(n, b):
        if n < b: return str(n)
        return base(n // b, b) + str(n % b)
    

答案 1 :(得分:1)

我主要修改了你的(已经非常好的)解决方案。递归的想法是将解决方案分解为更小的子问题。

在这种情况下,我们首先要获取一个地方的数字,这很简单:只需n%b。之后我们需要弄清楚如何将数字的其余部分转换为基数b。这是我们递归的部分,直到数字的其余部分为0,此时我们已经完成了。

   def base_recur(n,b):
        if n == 0:
            return []
        return  base_recur(n//b, b) + [n%b]

输出

   base_recur(887,7)
   [2, 4, 0, 5]

   base(5,3)
   [1, 2]

如果你想要一个字符串表示,你可以用join

包装结果
"".join(str(dig) for dig in base_recur(887,7))
'2405'

或者你可以定义递归函数来原生地返回一个字符串

   def base_recur(n,b):
        if n == 0:
            return ''
        return  base_recur(n//b, b) + str(n%b)

答案 2 :(得分:1)

进行递归时,效率更高的形式是使用tail recursion在每一步中进行一些计算并携带累加器,在最后一步中你在累加器中得到答案,因此你不要从递归调用返回的方式需要额外的工作,如果你能这样做很容易将它改成循环而反之亦然,那就是你必须在Haskell中做的事情,例如,如果你需要的话你可以用尾递归的形式进行循环计算。

现在这个问题可以解决这个问题

BASE='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' #until base 36, because why not :)

def base(n,b,acc=None):
    if acc is None:  # I need a accumulator, if I don't get one I provide one
        acc=[]
    if n < b:
        acc.append(BASE[n])
        return "".join(reversed(acc))
    else:
        n,d = divmod(n,b)      # n//b and n%b at once 
        acc.append(BASE[d])  
        return base(n,b,acc)   

(我使用一个列表作为累加器,因为在python字符串中是不可变的,所以任何改变它们的操作都会复制它,所以为了节省我的使用列表)

测试

>>> base(0,16)
'0'
>>> base(42,16)
'2A'
>>> base(5,3)
'12'
>>> base(420,25)
'GK'
>>> base(25,25)
'10'
>>> base(42,2)
'101010'