CS61A——函数递归的应用【Luhn algorithm】【Pingpong counting】【Hailstone recursionVer】

之前刷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/

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值