我正在尝试将此代码(给出二进制中连续 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
答案 0 :(得分:1)
这是原则性的方法:
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)
这里是愚蠢的,无原则的方式,基本上只是使用一个递归辅助函数,在它的闭包中改变变量,这只是为了演示递归如何基本上可以直接替换一个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
编辑:
如果不想使用辅助辅助函数,则需要额外的参数:
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)
答案 1 :(得分:0)
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
而不是二进制或 str
。相应地更改了解决方案。
答案 2 :(得分:0)
递归是一种函数式遗产,因此将其与函数式风格结合使用会产生最佳效果。这意味着避免诸如突变、变量重新分配和其他副作用之类的事情。我们可以用inductive reasoning原则性地解决问题-
n
只有一位,则已达到基本情况。如果 z
为 1 或返回 n
加 1 为最后的零,则返回连续零,z
n
有不止一位剩余。如果第一位是 1,则连续中断。产生当前的零条纹 z
,并在子问题 n >> 1
上重复出现,新的零条纹为 0n
有多个位且第一位为 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
函数已经接受了一个可迭代的输入,所以复制它几乎没有意义。
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
,我们可以在我们的函数中嵌入一个嵌套的帮助器 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
# ...
相关问答