[英]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
。 相應地更改了解決方案。
遞歸是一種函數式遺產,因此將其與函數式風格一起使用會產生最佳結果。 這意味着避免諸如突變、變量重新分配和其他副作用之類的事情。 我們可以用歸納推理有原則地解決問題——
n
只有一位,則已達到基本情況。 如果n
為 1,則返回零條紋z
或返回z
加 1 作為最后一個零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
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.