《Python算法竞赛攻略:从入门到降维打击》——第十一章

第11章:数学与数论

数学是算法的基石。在算法竞赛中,总有一些题目在“暴力”的外衣下,隐藏着一个数学或数论的内核。能否看穿这一点,并用高效的工具解决它,往往是区分“暴力选手”和“技巧选手”的关键。本章将聚焦于竞赛中最常遇到的数论与数学问题,并展示Python如何利用其丰富的标准库和语言特性,将复杂的数学计算“降维打击”为几行优雅的代码。

11.1 质数与约数:筛法、math.gcd, math.lcm

质数和约数是数论问题的起点,几乎贯穿了数论的全领域。

1. 质数 (Prime Number)

质数,又称素数,是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。

  • 判断单个质数:试除法
    最直观的方法是试除法:检查从2到 N\sqrt{N}N 的所有整数能否整除 NNN。如果都不能,那么 NNN 就是质数。这个方法的时间复杂度为 O(N)O(\sqrt{N})O(N ),适用于 NNN 比较大但判断次数不多的情况。

    import math
    
    def is_prime(n: int) -> bool:
        """判断一个数是否为质数"""
        if n < 2:
            return False
        for i in range(2, int(math.sqrt(n)) + 1):
            if n % i == 0:
                return False
        return True
    
    # 示例
    print(f"13 is prime: {
           
           is_prime(13)}")  # True
    print(f"20 is prime: {
           
           is_prime(20)}")  # False
    
  • 批量生成质数:埃氏筛 (Sieve of Eratosthenes)
    当需要找出一定范围(例如 11110610^6106)内所有质数时,O(N)O(\sqrt{N})O(N ) 的试除法会超时。此时,更高效的策略是“筛法”。埃氏筛是其中最经典、最常用的算法。

    其思想是:从2开始,将每个质数的倍数都标记为合数。一个数如果没有被前面的质数标记过,那它一定是质数。

    def prime_sieve(n: int) -> list[bool]:
        """
        埃氏筛法,返回一个布尔列表,is_prime[i]为True表示i是质数。
        时间复杂度: O(N log log N)
        """
        is_prime = [True] * (n + 1)
        is_prime[0] = is_prime[1] = False  # 0和1不是质数
        for i in range(2, int(n**0.5) + 1):
            if is_prime[i]:
                # i的倍数(从i*i开始)都不是质数
                for j in range(i * i, n + 1, i):
                    is_prime[j] = False
        return is_prime
    
    # 找出100以内的所有质数
    limit = 100
    primes_bool = prime_sieve(limit)
    prime_numbers = [i for i, is_p in enumerate(primes_bool) if is_p]
    print(f"Primes up to {
           
           limit}: {
           
           prime_numbers}")
    # 输出: Primes up to 100: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
    

    埃氏筛的代码简洁,效率极高,足以应对绝大多数竞赛场景。

2. 约数 (Divisor)

  • 最大公约数 (GCD) 和 最小公倍数 (LCM)
    在C++中,你可能需要自己手写欧几里得算法(辗转相除法)来求GCD。但在Python中,这完全是降维打击math库已经为我们提供了现成、高效的函数。

    • math.gcd(a, b): 计算a和b的最大公约数。
    • math.lcm(a, b): 计算a和b的最小公倍数 (Python 3.9+)。
    import math
    
    a, b = 48, 18
    
    # 最大公约数
    gcd_val = math.gcd(a, b)
    print(f"GCD 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱看烟花的码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值