欢迎光临
我们一直在努力

【Python神技巧】一行代码判断质数,数学题秒杀神器!

前言

大家好,这里是 Charming讲Python编码小技巧 系列专栏。每天分享一个 30-seconds-of-python 仓库中的神级写法,助你告别“屎山”代码,写出让人眼前一亮的 Pythonic 风格!

小技巧内容描述

质数(素数)是指只能被1和它本身整除的大于1的自然数。在编程面试和算法题中,判断质数是一个常见问题。今天教你一个高效且优雅的解决方案,短短几行代码就能搞定!

from math import sqrt

def is_prime(n):
if n <= 1 or (n % 2 == 0 and n > 2):
return False
return all(n % i for i in range(3, int(sqrt(n)) + 1, 2))

就这么简单!让我来详细解释一下为什么这么写。

为什么这么用?

核心原理:数学优化的魔力

这个技巧的核心在于利用数学性质进行优化,避免不必要的计算:

  • 边界处理:

    • n <= 1:小于等于1的数都不是质数
    • n % 2 == 0 and n > 2:大于2的偶数都不是质数
  • 关键优化:

    • 只需要检查到 sqrt(n)(平方根)就够了!因为如果n有因子,至少有一个因子小于等于它的平方根
    • 只检查奇数(从3开始,步长为2),跳过所有偶数
  • all()函数:

    • all() 函数检查所有元素是否都为True
    • 如果 n % i 都不为0,说明n不能被这些数整除,是质数
  • 举个栗子

    # 基础测试
    print(is_prime(2)) # True (唯一的偶质数)
    print(is_prime(3)) # True
    print(is_prime(11)) # True
    print(is_prime(17)) # True
    print(is_prime(97)) # True

    # 非质数
    print(is_prime(1)) # False
    print(is_prime(4)) # False
    print(is_prime(15)) # False
    print(is_prime(100)) # False
    print(is_prime(121)) # False (11*11)

    理解检查范围

    以 is_prime(17) 为例:

    • sqrt(17) ≈ 4.12
    • range(3, 5, 2) = [3]
    • 检查:17 % 3 = 2 ≠ 0
    • all() 返回 True → 17是质数

    以 is_prime(15) 为例:

    • sqrt(15) ≈ 3.87
    • range(3, 4, 2) = [3]
    • 检查:15 % 3 = 0
    • all() 返回 False → 15不是质数

    更多实用场景

    场景一:密码学应用 – 生成大质数

    import random

    def generate_large_prime(bits=64):
    """生成指定位数的大质数"""
    while True:
    # 生成一个奇数
    n = random.getrandbits(bits) | 1
    if is_prime(n):
    return n

    # 测试
    large_prime = generate_large_prime(32)
    print(f"生成的32位质数: {large_prime}")
    print(f"验证: {is_prime(large_prime)}") # True

    场景二:密码强度检测 – 质数密码奖励

    def check_password_with_bonus(password):
    """检查密码,如果是质数长度给予奖励"""
    password_len = len(password)

    if password_len < 8:
    print("密码长度不足8位")
    return False

    if is_prime(password_len):
    print(f"密码长度 {password_len} 是质数!获得'数学达人'徽章!")
    return True
    else:
    print(f"密码长度 {password_len} 位,注册成功")
    return True

    # 测试
    check_password_with_bonus("abc12345") # 长度8 (非质数)
    check_password_with_bonus("abc1234567") # 长度10 (非质数)
    check_password_with_bonus("abc12345678") # 长度11 (质数!)

    场景三:数据分页优化 – 质数页码

    def optimize_page_numbers(total_items, items_per_page):
    """优化分页,优先显示质数页码"""
    total_pages = (total_items + items_per_page 1) // items_per_page

    # 获取所有质数页码
    prime_pages = [p for p in range(1, total_pages + 1) if is_prime(p)]

    print(f"总页数: {total_pages}")
    print(f"质数页码: {prime_pages}")

    # 返回推荐页码(优先质数)
    return prime_pages

    # 测试
    optimize_page_numbers(100, 10) # 10页,质数页: [2, 3, 5, 7]

    场景四:找质数对 – 哥德巴赫猜想验证

    def find_prime_pairs(n):
    """找出所有两个质数之和等于n的组合"""
    pairs = []
    for i in range(2, n // 2 + 1):
    if is_prime(i) and is_prime(n i):
    pairs.append((i, n i))
    return pairs

    # 验证哥德巴赫猜想(每个大于2的偶数可以表示为两个质数之和)
    for even_num in [10, 14, 20, 28, 100]:
    pairs = find_prime_pairs(even_num)
    print(f"{even_num} = {pairs}")

    性能对比

    让我们看看这个方法和其他方法相比性能如何:

    import time

    # 方法1:使用sqrt优化(推荐)
    def method1(n):
    if n <= 1 or (n % 2 == 0 and n > 2):
    return False
    return all(n % i for i in range(3, int(sqrt(n)) + 1, 2))

    # 方法2:暴力检查所有数
    def method2(n):
    if n <= 1:
    return False
    for i in range(2, n):
    if n % i == 0:
    return False
    return True

    # 方法3:检查到n,但不使用all()
    def method3(n):
    if n <= 1:
    return False
    for i in range(2, int(n ** 0.5) + 1):
    if n % i == 0:
    return False
    return True

    # 性能测试
    test_number = 9999991 # 一个大质数

    # 测试方法1
    start = time.time()
    result1 = method1(test_number)
    print(f"方法1(sqrt优化): {time.time() start:.6f}秒, 结果: {result1}")

    # 测试方法2
    start = time.time()
    result2 = method2(test_number)
    print(f"方法2(暴力): {time.time() start:.6f}秒, 结果: {result2}")

    # 测试方法3
    start = time.time()
    result3 = method3(test_number)
    print(f"方法3(循环): {time.time() start:.6f}秒, 结果: {result3}")

    结果对比:

    • 方法1(sqrt优化):最快,简洁优雅
    • 方法2(暴力):最慢,对于大数几乎不可用
    • 方法3(循环):次快,但代码较长

    进阶技巧:找出指定范围内的所有质数

    方法1:简单遍历

    def find_primes_in_range(start, end):
    """找出指定范围内的所有质数"""
    return [n for n in range(start, end + 1) if is_prime(n)]

    # 找出1到100的所有质数
    primes = find_primes_in_range(1, 100)
    print(f"1到100的质数: {primes}")
    print(f"共 {len(primes)} 个")

    方法2:埃拉托斯特尼筛法(更高效)

    def sieve_of_eratosthenes(n):
    """埃拉托斯特尼筛法找出小于等于n的所有质数"""
    if n < 2:
    return []

    sieve = [True] * (n + 1)
    sieve[0] = sieve[1] = False

    for i in range(2, int(n ** 0.5) + 1):
    if sieve[i]:
    sieve[i*i : n+1 : i] = [False] * len(sieve[i*i : n+1 : i])

    return [i for i, is_prime in enumerate(sieve) if is_prime]

    # 测试
    primes = sieve_of_eratosthenes(100)
    print(f"1到100的质数: {primes}")
    print(f"共 {len(primes)} 个")

    # 性能对比
    import time

    n = 1000000

    start = time.time()
    primes1 = find_primes_in_range(1, n)
    print(f"简单遍历法: {time.time() start:.4f}秒")

    start = time.time()
    primes2 = sieve_of_eratosthenes(n)
    print(f"筛法: {time.time() start:.4f}秒")

    质数趣味知识

  • 最大的已知质数:截至2024年,最大的已知质数是 2^82,589,933 − 1,有近2500万位数字
  • 梅森质数:形如 2^p − 1 的质数,已知51个梅森质数
  • 孪生质数:相差2的质数对,如 (3,5)、(5,7)、(11,13)
  • 质数定理:小于n的质数数量约为 n/ln(n)
  • 总结

    这个"判断质数"的技巧之所以如此优雅,是因为:

  • 数学优化:利用质数的数学性质,大幅减少计算量
  • 代码简洁:核心逻辑只有几行
  • 性能优秀:时间复杂度 O(√n),远优于暴力法的 O(n)
  • Pythonic:使用 all() 函数,代码优雅易读
  • 实用性强:密码学、算法题、数据分析等领域都有应用
  • 下次遇到需要判断质数的场景,不妨试试这个技巧,让你的代码既简洁又高效!


    今日小技巧: all(n % i for i in range(3, int(sqrt(n)) + 1, 2)) – 高效判断质数

    适用场景: 密码学、算法题、数据验证、数学计算等

    点赞收藏,每天学一个Python神技巧!

    赞(0)
    未经允许不得转载:171主机测评 » 【Python神技巧】一行代码判断质数,数学题秒杀神器!
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址