繁体   English   中英

将while循环转换为递归

[英]Turning a while loop to a recursion

我正在尝试将此代码(给出二进制中连续 0 的最大数量)转换为递归代码。 我尝试了很多方法,但结果是错误的。 这是使用 while 循环的代码:

def consecutivezeros(N):
    if N==0 :
        return 1
    # variable to store the length
    # of longest consecutive 0's
    maxm = -1

    # to temporary store the
    # consecutive 0's
    cnt = 0
    while (N):
        if (not (N & 1)):
            cnt += 1
            N >>= 1
            maxm = max(maxm, cnt)
        else:
            maxm = max(maxm, cnt)
            cnt = 0
            N >>= 1

    return maxm

以下是原则方法:

def consecutivezeros(N):
    if N == 0:
        return 1
    def _consecutivezeros(N, maxm, cnt):
        if not N:
            return maxm
        elif (not (N & 1)):
            new_cnt = cnt + 1
            return _consecutivezeros(N>>1, max(maxm, new_cnt), new_cnt)
        else:
            return _consecutivezeros(N>>1, max(maxm, cnt), 0)
    return _consecutivezeros(N, -1, 0)

这是愚蠢的,没有原则的方式,基本上只是使用递归帮助器 function 在它的闭包中改变变量,这只是为了演示递归如何基本上可以直接替换while循环,但它不是很优雅:

def consecutivezeros(N):
    if N == 0:
        return 1
    maxm = -1
    cnt = 0
    def _looper():
        nonlocal maxm, cnt, N
        if not N:
            return
        if (not (N & 1)):
            cnt += 1
            maxm = max(maxm, cnt)
        else:
            maxm = max(maxm, cnt)
            cnt = 0
        N >>= 1
    _looper(N)
    return maxm

编辑:

如果您不想使用辅助助手 function,则需要额外的 arguments:

def consecutivezeros(N, _maxm=-1, _cnt=0, _first=True):
    if N == 0 and _first:
        return 1
    elif not N:
        return _maxm
    elif (not (N & 1)):
        incr = _cnt + 1
        return consecutivezeros(N>>1, max(_maxm, incr), incr, False)
    else:
        return consecutivezeros(N>>1, max(_maxm, _cnt), 0, False)
def rec_count(s: str, c: int = 0, m: int = 0):
    if s:
        if s[0] == "0":
            if (c := c+1) > m:
                m = c

            return rec_count(s[1:], m=m, c=c)
        else:
            return rec_count(s[1:], m=m)
    else:
        return m


N = 100000100101
print(rec_count(s=str(N)))
# 5

编辑:根据评论,输入是int而不是 binary 或str 相应地更改了解决方案。

递归是一种函数式遗产,因此将其与函数式风格一起使用会产生最佳结果。 这意味着避免诸如突变、变量重新分配和其他副作用之类的事情。 我们可以用归纳推理有原则地解决问题——

  1. 如果输入n只有一位,则已达到基本情况。 如果n为 1,则返回零条纹z或返回z加 1 作为最后一个零
  2. (归纳) n剩余多于一位。 如果第一位是 1,则连续中断。 产生当前的零条纹z ,并在子问题n >> 1上重复出现,新的零条纹为 0
  3. (归纳) n有多个位,并且第一位是 0。在子问题n >> 1上递归,并带有递增的零条纹
def consecutive_zeroes(n, z = 0):
  if n < 2:                                      # 1
    yield z if n == 1 else z + 1
  elif n & 1:                                    # 2
    yield z
    yield from consecutive_zeroes(n >> 1, 0)
  else:                                          # 3
    yield from consecutive_zeroes(n >> 1, z + 1)

请注意,生成器与max逻辑分离。 内置的max function 已经接受了一个可迭代的输入,所以复制它没有什么意义。

for x in range(20):
  print(f"{x:b}", max(consecutive_zeroes(x)))
0 1
1 0
10 1
11 0
100 2
101 1
110 1
111 0
1000 3
1001 2
1010 1
1011 1
1100 2
1101 1
1110 1
1111 0
10000 4
10001 3
10010 2
10011 2
for x in range(60, 80):
  print(f"{x:b}", max(consecutive_zeroes(x)))
111100 2
111101 1
111110 1
111111 0
1000000 6
1000001 5
1000010 4
1000011 4
1000100 3
1000101 3
1000110 3
1000111 3
1001000 3
1001001 2
1001010 2
1001011 2
1001100 2
1001101 2
1001110 2
1001111 2
for x in range(500, 520):
  print(f"{x:b}", max(consecutive_zeroes(x)))
111110100 2
111110101 1
111110110 1
111110111 1
111111000 3
111111001 2
111111010 1
111111011 1
111111100 2
111111101 1
111111110 1
111111111 0
1000000000 9
1000000001 8
1000000010 7
1000000011 7
1000000100 6
1000000101 6
1000000110 6
1000000111 6

防止参数泄露

如果您不希望像z这样的额外参数或期望调用者需要max ,我们可以在我们的 function 中嵌入一个嵌套帮助器loop ——

def consecutive_zeroes(n):          # <- new wrapper, with no leaked parameters
  def loop(n, z):                   # <- our function above, renamed to loop
    if n < 2:
      yield z if n == 1 else z + 1
    elif n & 1:
      yield z
      yield from loop(n >> 1, 0)
    else:
      yield from loop(n >> 1, z + 1)
  return max(loop(n, 0))            # <- max 

现在,当您调用它时,调用者不再需要max -

for x in range(20):
  print(f"{x:b}", consecutive_zeroes(x))   # <- no need to call max

# ...

相关问答

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM