Python 学习笔记之练习题 1

递归

递归算法是一种直接或者间接调用自身函数或者方法的算法。
递归算法的实质是把问题分解为规模更小的同类子问题,然后递归调用方法来表示问题的解。

  1. 该问题的解可以分解为几个子问题的解;
  2. 这个问题与分解后的子问题,除了数据规模的不同,求解思路完全一样;
  3. 存在递归终止条件,即,必须有一个明确的递归结束条件,称之为递归出口。

数组求和

对 1 到 n 这 n 个数字进行求和,可以看做是 n 加上 1 到 n-1 这 n-1 个数字求和的结果;并以此逐步分解,直到最后是 0 与 1 进行求和。

def sum_func(n):
    if n == 1:
        return 1
    else:
        return n + sum_func(n-1)

汉诺塔问题

汉诺塔是典型的可以用 分治算法 解决的问题,以下内容是采用分治思想的递归算法。

问题描述:
有三个盘座A、B、C,A上有64个盘子,盘子大小不等,大在下,小在上。若要把盘子从A移到B,每次只能移动一个,且移动过程中,3个座上始终保持:大在上,小在下。

问题分析:

  1. 如果只有一个盘子,则不需要借助C,直接从A移动到B。
  2. 如果只有两个盘子,则可以先把A的最上面一个盘子2移动到C;再将盘子1移动到B;然后将盘子2移动到B。这说明了借助C可以将2个盘子从A移动到B;同样,也说明借助B可以将2个盘子从A移动到C。
  3. 如果有3个盘子,那么根据2个盘子的结论,可以借助B将盘子1上的两个盘子(盘子2和盘子3)从A移动到C;将盘子1从A移动到B,A则变为空座;借助A座,将C上的两个盘子移动到B。
  4. 以此类推,上述思路可以扩展到 n 个盘子的情况,将较小的 n-1 个盘子看做一个整体,也就是我们要求的子问题,初始A上有 n 个盘子,B、C上为空;可以借助B,将A上面的 n-1 个盘子从A移动到C;将A上最大的盘子1移动到B,A为空座;可以借助B,将C上的 n-2 个盘子从C移动到A;将C上最大的盘子2(从整体看,为第二大)移动到B,C为空座;…

代码示例:

def move(n, source, target):
    print('The', n, 'th', 'plate move: ', source, '------>', target)

def hanoi(n, source, temp, target):
    if n == 1:
        # only one plate, move it directly from source to target
        move(n, source, target)
    else:
        # move the top n-1 plates from source to temp through target
        hanoi(n-1, source, target, temp)
        # move the n plate(the largest and lowest plate) from source to target
        move(n, source, target)
        # move the top n-1 plates from temp to target through source
        hanoi(n-1, temp, source, target)
hanoi(3, 'A', 'C', 'B')

计算阶乘

# 实现阶乘
def factorial_z(n):
    if n == 1:
        return n
    return n*factorial_z(n-1)

计算组合数

# 求组合数
def combination_z(n, m):
    if m == n:
        return 1
    elif m == 1:
        return n
    else:
        return combination_z(n-1, m-1) + combination_z(n-1, m)

在不使用标准库的情况下,为 C k n C_k^{n} Ckn 编写一个函数。

C_n^k1

def factorial(n):
	if n==0:
		return 1
return (n * factorial(n-1) )

def nCr(n,k):
	return factorial(n)/(factorial(k) * factorial(n-k))

对于大的数字,存在更好的解决方案,没有必要三次调用阶乘函数。
此外,如果分子和分母都很大,很可能会发生数字溢出。

C_n^k2

def nCr_norecur(n,k):
	r=1
	for i in range(k):
		r *= n-i
		r = r / (i+1)
	return r

Coding Challenge

Fizz

给你一个整数比如 100,需要输出一个列表。列表中的每个元素,如果能被 3 整除则输出 ‘Fizz’。

def fizz(n):
    res = []
    for i in range(1, n + 1):
        if i % 3 == 0:
            res.append('Fizz')
        else:
            res.append(str(i))
    return res

FizzBuzz

给你一个整数比如 100,需要输出一个列表。列表中的每个元素,如果能被 3 整除则输出 ‘Fizz’,如果被 5 整除则输出 ‘Buzz’,如果能同时被 3 和 5 整除,则输出 ‘FizzBuzz’。

def fizzbuzz(n):
    res = []
    for i in range(1, n + 1):
        if i % 3 == 0 and i % 5 == 0:
            res.append('FizzBuzz')
        elif i % 3 == 0 and i % 5 != 0:
            res.append('Fizz')
        elif i % 3 != 0 and i % 5 == 0:
            res.append('Buzz')
        else:
            res.append(str(i))
    return res

FizzBuzzPrime

在 FizzBuzz 的基础上,识别质数。如果是质数,则输出为 “Prime”。所以代码中我们需要新增一个判断是否为质数的 Function。

def is_prime(n):
    if n == 1:
        return False
    else:
        for i in range(2, int(math.sqrt(n)) + 1):
            if n % i == 0:
                return False
        else:
            return True


def fizzbuzzprime(n):
    res = []
    for i in range(1, n + 1):
        if is_prime(i):
            res.append('Prime')
        elif i % 3 == 0 and i % 5 == 0:
            res.append('FizzBuzz')
        elif i % 3 == 0:
            res.append('Fizz')
        elif i % 5 == 0:
            res.append('Buzz')
        else:
            res.append(str(i))
    return res

FizzBuzzPrimePi

在 FizzBuzzPrime 的基础上, 如果数字是 ‘Pi’ 前 n 位字符串的一个连续子集,则需要输出 ‘Pi’。
题目会给定 n 和 p 两个数字,比如 n=15,p=3。那么答案是 [‘Pi’, ‘Prime’, ‘Pi’, ‘Pi’, ‘Buzz’, ‘Fizz’, ‘Prime’, ‘8’, ‘Fizz’, ‘Buzz’, ‘Prime’, ‘Fizz’, ‘Prime’, ‘Pi’, ‘FizzBuzz’]。
题目中的 1, 3, 4, 14都输出为 “Pi”,是因为题目给定 p=3,也就是说只要是 314 的连续子集,则对应位置的数字要输出为 ‘Pi’。(如果 p=4,则只要是 3141 的连续子集,则对应位置的数字要输出为 ‘Pi’)。

  1. 问题就在于怎么样计算 pi,因为 math 模块中的 pi 只精确到小数点后 16 位,当题目中 p 大于 17 时就无法使用 python 内置的 pi。
  2. 考虑 n 和 p 之间的关系,是否存在一个值,当 p 大于这个值时,所有 n 的输出都是 pi?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值