之前刷CS61A在recursion部分遇到几个好玩的问题,分享一下思路:
1、The Luhn algorithm
Used to verify that a credit card numbers is valid.
a)From the rightmost digit, which is the check digit, moving left, double the value of every second digit; if product of this doubling operation is greater than 9 (e.g., 7 * 2 = 14), then sum the digits of that product (e.g., 14: 1 + 4 = 5)
b)Take the sum of all the digits
Luhn算法(Luhn algorithm),也称为“模10”(Mod 10)算法,是一种简单的校验和算法,一般用于验证身份识别码,例如发卡行识别码、国际移动设备辨识码(IMEI),美国国家提供商标识号码,或是加拿大社会保险号码。该算法由IBM科学家Hans Peter Luhn创造,专利于1954年1月6日申请。
它根据原始标识号,把每隔一个数字的值扩大一倍。然后把各个单独数字的值加在一起(如果扩大一倍后的值为2个数字,就把这两个数字分别相加)。如果相加之后可以被10整除,那么这个标识号就是合法的。
编写一个程序,接受一个任意长度的标识号,并根据Luhn公式确定这个标识号是否合法。这个程序在读取下一个字符之前必须处理之前所读取的那个字符。
做法:
用递归的方法,每次从右往左取两位数依次处理
def luhn_sum(n):
if n < 10:
return n
else:
last,all_but_last = n % 100,n // 100
if (last // 10)*2 > 9:
last_two_sum = last % 10 + (last // 10)*2 - 9
else:
last_two_sum = last % 10 + (last // 10)*2
return last_two_sum + luhn_sum(all_but_last)
官方答案,用了三个函数嵌套,着实看着高级:
def sum_digits(n):
if n < 10:
return n
else:
last = n % 10
all_but_last = n // 10
sum = last + sum_digits(all_but_last)
return sum
def luhn_sum(n):
if n < 10:
return n
else:
last = n % 10
all_but_last = n // 10
print('all_but_last_first',all_but_last)
return last + luhn_sum_double(all_but_last)
def luhn_sum_double(n):
last = n % 10
all_but_last = n // 10
luhn_digit = sum_digits(last * 2)
if n < 10:
return luhn_digit
else:
return luhn_digit + luhn_sum(all_but_last)
测试:
luhn_sum(67152) #15
luhn_sum(152) #4
luhn_sum(2) #2
luhn_sum(32) #8
luhn_sum(5105105105105100) #20
2、Pingpong counting
来自第三次作业的一道题:
Q2: Ping-pong
The ping-pong sequence counts up starting from 1 and is always either counting up or counting down. At element k, the direction switches if k is a multiple of 8 or contains the digit 8. The first 30 elements of the ping-pong sequence are listed below, with direction swaps marked using brackets at the 8th, 16th, 18th, 24th, and 28th elements:
IndexNum 1 2 3 4 5 6 7 [8] 9 10 11 12 13 14 15 [16] 17 [18] 19 20 21 22 23 [24] 25 26 27 [28] 29 30
PPValues 1 2 3 4 5 6 7 [8] 7 6 5 4 3 2 1 [0] 1 [2] 1 0 -1 -2 -3 [-4] -3 -2 -1 [0] -1 -2
Implement a function pingpong that returns the nth element of the ping-pong sequence without using any assignment statements.
You may use the function num_eights, which you defined in the previous question.
Use recursion - the tests will fail if you use any assignment statements.
大概的意思就是:一个从1开始,每次递增1的数列有n个数,当n为8的倍数(16,24)或者含有8的数(如18,28)时,数列会转变成每次递减1,求该数列第n个数对应的值。
一开始用的for循环的方法做了个容易理解版的:
def pingpong(n):
pingpongValue,oneloopScore = 0,1
for index in range(n):
if i == 0 :
pingpongValue += 1
elif num_eights(i)>0 or (i)%8 ==0:
oneloopScore = 0-oneloopScore
pingpongValue += oneloopScore
else:
pingpongValue += oneloopScore
return pingpongValue
但是官方不给用循环,就要用函数递归呀,不过还好给了提示,用一个helper function执行递归,于是有了:
def pingpong(n):
def pingpongLooper(index,pingpongValue,direction):
index += 1
pingpongValue += direction
if index == n:
return pingpongValue
elif num_eights(index)>0 or (index)%8 ==0:
direction = 0-direction
return pingpongLooper(index,pingpongValue,direction)
else:
return pingpongLooper(index,pingpongValue,direction)
return pingpongLooper(index=0,pingpongValue=0,direction=1)
注:里面的num_eights函数的前一题目(判断一个输入的数,字面上有几个数字8,80->1个,188->2个,8888->4个…):
def num_eights(pos):
if pos < 10 and pos%10 ==8:
return 1
elif pos < 10 and pos%10 !=8:
return 0
elif pos%10 ==8:
return 1 + num_eights(pos//10)
else:
return 0 + num_eights(pos//10)
3、Hailstone
大名鼎鼎的 冰雹猜想
First, pick a positive integer n as the start. If n is even, divide it by 2. If n is odd, multiply it by 3 and add 1. Repeat this process until n is 1. Write a recursive version of hailstone that prints out the values of the sequence and returns the number of steps.
冰雹猜想(也叫作3n+1问题,角古猜想)的内容是:一个正整数n,如果它是偶数就除以2,如果它是奇数就乘以3再加1,经过若干次这样的判断,它最终将变成1。这个由两个判断语句组成的一个猜想看似简单,但是它的正确性迄今为之都还不能确定,没有一个反列能够推翻该猜想,也没有一个严谨的论证过程证明该式一定正确。
第一次用for循环解答:
def hailstoneForloop(n):
print(n)
count = 1
while n > 1:
count += 1
if n%2 ==0:
n = n//2
print(n)
else:
n = 3*n+1
print(n)
return count
不够简洁,不过那时候还是小白也没纠结怎么优化。后来到recursion那章,再用recrusion的思路写,高阶多了:
def hailstoneRecursionAnswer(n):
print(n)
if n == 1:
return 1
elif n % 2 == 0:
return 1 + hailstoneRecursionAnswer(n // 2)
else:
return 1 + hailstoneRecursionAnswer(3 * n + 1)
Pass这几道,深刻感受到recursion的有趣啦
附上 Citation :
(自己不好翻译咯,中文解释都参考的这些网友的)
https://blog.csdn.net/bobshui/article/details/122311479
https://blog.51cto.com/u_11207102/3275132
https://juejin.cn/post/6883095604830928904
https://inst.eecs.berkeley.edu/~cs61a/sp22/