跳转至

程序设计题解析

第1题:回文数判断与生成

题目: 编写程序,判断一个整数是否为回文数,并找出指定范围内的所有回文数。

方法1:数值反转法(最直观)

Python
def is_palindrome(n):
    """判断整数是否为回文数(数值方法)"""
    if n < 0:
        return False
    if n < 10:
        return True
    original = n
    reversed_num = 0
    while n > 0:
        digit = n % 10           # 取出末位数字
        reversed_num = reversed_num * 10 + digit  # 逐位构建反转数
        n = n // 10              # 去掉末位
    return original == reversed_num

def find_palindromes(start, end):
    """找出 [start, end] 范围内的所有回文数"""
    result = []
    for n in range(start, end + 1):
        if is_palindrome(n):
            result.append(n)
    return result

# 测试
print(is_palindrome(121))    # True
print(is_palindrome(-121))   # False
print(is_palindrome(12321))  # True
print(find_palindromes(100, 200))
# [101, 111, 121, 131, 141, 151, 161, 171, 181, 191]

方法2:半数反转法(优化版)

Python
def is_palindrome_v2(n):
    """只反转一半数字进行比较"""
    if n < 0:
        return False
    if n < 10:
        return True
    # 末尾为0的数不可能是回文数(除了0本身)
    if n % 10 == 0:
        return False

    reversed_half = 0
    while n > reversed_half:
        reversed_half = reversed_half * 10 + n % 10
        n = n // 10

    # 偶数位:n == reversed_half
    # 奇数位:n == reversed_half // 10(去掉中间位)
    return n == reversed_half or n == reversed_half // 10

# 测试
print(is_palindrome_v2(1221))   # True(偶数位:12 == 12)
print(is_palindrome_v2(12321))  # True(奇数位:12 == 123//10=12)
print(is_palindrome_v2(12345))  # False

🔑 知识点

知识点 说明
n % 10 取出整数末位数字
n // 10 去掉整数末位数字
反转数字 rev = rev * 10 + n % 10,逐位构建
边界条件 负数不是回文数;个位数是回文数;末尾为0的非零数不是回文数
半数反转 只需反转一半即可判断,效率更高

反转数字过程图解(以 121 为例):

Text Only
初始: n=121, rev=0

第1轮: digit = 121 % 10 = 1
       rev = 0 * 10 + 1 = 1
       n = 121 // 10 = 12

第2轮: digit = 12 % 10 = 2
       rev = 1 * 10 + 2 = 12
       n = 12 // 10 = 1

第3轮: digit = 1 % 10 = 1
       rev = 12 * 10 + 1 = 121
       n = 1 // 10 = 0

结束: 121 == 121 → True
📖 拓展
Python
# 拓展1:回文数生成(构造法,比逐个判断快得多)
def generate_palindromes(n_digits):
    """生成指定位数的所有回文数"""
    palindromes = []
    half_len = (n_digits + 1) // 2
    start = 10 ** (half_len - 1)
    end = 10 ** half_len

    for half in range(start, end):
        s = str(half)
        if n_digits % 2 == 0:
            palindromes.append(int(s + s[::-1]))
        else:
            palindromes.append(int(s + s[-2::-1]))
    return palindromes

print(generate_palindromes(3))  # 3位回文数
# [101, 111, 121, ..., 999]

# 拓展2:最长回文数对
def nearest_palindrome(n):
    """找离 n 最近的回文数"""
    if is_palindrome(n):
        return n
    low = n - 1
    high = n + 1
    while True:
        if is_palindrome(low):
            return low
        if is_palindrome(high):
            return high
        low -= 1
        high += 1

# 拓展3:回文素数(既是回文数又是素数)
def palindrome_primes(limit):
    """找出 limit 以内的回文素数"""
    from math import sqrt
    def is_prime(n):
        if n < 2: return False
        for i in range(2, int(sqrt(n)) + 1):
            if n % i == 0: return False
        return True
    return [n for n in range(2, limit + 1)
            if is_palindrome(n) and is_prime(n)]

print(palindrome_primes(200))
# [2, 3, 5, 7, 11, 101, 131, 151, 181, 191]

📌 记忆要点

  • 数字反转核心:rev = rev * 10 + n % 10,配合 n //= 10

  • 回文数判断:反转后与原数比较

  • 负数、末尾为0的非零数不是回文数

  • 半数反转法更高效,只反转一半即可判断


第2题:素数筛选与统计

题目: 编写程序,使用筛选法找出指定范围内的所有素数,并统计素数个数及占比。

方法1:逐个判断法(最直观)

Python
def is_prime(n):
    """判断 n 是否为素数"""
    if n < 2:
        return False
    if n == 2:
        return True
    if n % 2 == 0:
        return False
    # 只需判断到 sqrt(n)
    for i in range(3, int(n ** 0.5) + 1, 2):
        if n % i == 0:
            return False
    return True

def find_primes(start, end):
    """找出 [start, end] 内的所有素数"""
    primes = [n for n in range(max(start, 2), end + 1) if is_prime(n)]
    return primes

def prime_stats(start, end):
    """统计素数信息"""
    primes = find_primes(start, end)
    total = end - start + 1
    count = len(primes)
    ratio = count / total * 100 if total > 0 else 0
    max_prime = max(primes) if primes else None

    print(f"范围[{start},{end}]内素数: {primes}")
    print(f"素数个数: {count}, 占比: {ratio:.1f}%")
    print(f"最大素数: {max_prime}")
    return primes

# 测试
print(is_prime(7))   # True
print(is_prime(1))   # False
prime_stats(2, 30)
# 素数: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
# 个数: 10, 占比: 33.3%, 最大: 29

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

Python
def prime_sieve(limit):
    """埃拉托斯特尼筛法:找出 [2, limit] 内所有素数"""
    if limit < 2:
        return []
    # 初始化:假设所有数都是素数
    is_prime = [True] * (limit + 1)
    is_prime[0] = is_prime[1] = False

    # 从 2 开始筛选
    for i in range(2, int(limit ** 0.5) + 1):
        if is_prime[i]:
            # 将 i 的所有倍数标记为非素数
            for j in range(i * i, limit + 1, i):
                is_prime[j] = False

    return [n for n in range(2, limit + 1) if is_prime[n]]

def sieve_stats(limit):
    """筛法统计"""
    primes = prime_sieve(limit)
    count = len(primes)
    ratio = count / (limit - 1) * 100  # [2, limit] 共 limit-1 个数
    max_prime = max(primes) if primes else None

    print(f"范围[2,{limit}]内素数: {primes}")
    print(f"素数个数: {count}, 占比: {ratio:.1f}%")
    print(f"最大素数: {max_prime}")
    return primes

# 测试
print(prime_sieve(30))
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
sieve_stats(30)

🔑 知识点

知识点 说明
素数定义 大于1的自然数,只能被1和自身整除
int(n ** 0.5) + 1 只需判断到 sqrt(n),大幅减少循环次数
筛法原理 从2开始,将每个素数的倍数标记为非素数
i * i 起始 筛法中从 i*i 开始标记,因为更小的倍数已被更小的素数筛掉
列表推导式 [n for n in range(...) if condition] 简洁筛选

筛法过程图解(limit = 10):

Text Only
1
2
3
4
5
6
7
8
9
初始: [2, 3, 4, 5, 6, 7, 8, 9, 10] 全部标记为 True

i=2: 标记 4, 6, 8, 10 为 False
     [2, 3, ×, 5, ×, 7, ×, 9, ×]

i=3: 标记 9 为 False
     [2, 3, ×, 5, ×, 7, ×, ×, ×]

结果: [2, 3, 5, 7]
📖 拓展
Python
# 拓展1:分解质因数
def prime_factors(n):
    """将 n 分解为质因数的乘积"""
    factors = []
    d = 2
    while d * d <= n:
        while n % d == 0:
            factors.append(d)
            n //= d
        d += 1
    if n > 1:
        factors.append(n)
    return factors

print(prime_factors(84))  # [2, 2, 3, 7] → 84 = 2² × 3 × 7

# 拓展2:判断互素
def are_coprime(a, b):
    """判断两个数是否互素(最大公约数为1)"""
    from math import gcd
    return gcd(a, b) == 1

# 拓展3:孪生素数(相差2的素数对)
def twin_primes(limit):
    """找出 limit 以内的孪生素数对"""
    primes = prime_sieve(limit)
    prime_set = set(primes)
    twins = [(p, p + 2) for p in primes
             if p + 2 in prime_set]
    return twins

print(twin_primes(50))
# [(3,5), (5,7), (11,13), (17,19), (29,31), (41,43)]

📌 记忆要点

  • 判断素数:只需除到 sqrt(n),注意 0 和 1 不是素数

  • 筛法核心:标记倍数,从 i*i 开始(更小的倍数已被筛掉)

  • 筛法效率远高于逐个判断,适合大范围找素数

  • 列表推导式可简洁地筛选满足条件的元素


第3题:数字拆分与重组

题目: 编写程序,对输入的正整数进行数字拆分、排序和重组操作。

方法1:数值运算法(最直观)

Python
def split_digits(n):
    """将整数拆分为各位数字列表"""
    if n == 0:
        return [0]
    digits = []
    while n > 0:
        digits.append(n % 10)   # 取末位
        n //= 10                 # 去末位
    digits.reverse()             # 反转为正序
    return digits

def sort_digits(n):
    """将各位数字升序排列组成新整数"""
    digits = split_digits(n)
    digits.sort()                # 升序排列
    result = 0
    for d in digits:
        result = result * 10 + d
    return result

def reverse_number(n):
    """将整数各位数字反转"""
    digits = split_digits(n)
    digits.reverse()             # 反转
    result = 0
    for d in digits:
        result = result * 10 + d
    return result

def max_min_diff(n):
    """数字重排为最大数和最小数,计算差值"""
    digits = split_digits(n)
    digits_sorted = sorted(digits)         # 升序
    digits_desc = sorted(digits, reverse=True)  # 降序

    max_num = 0
    for d in digits_desc:
        max_num = max_num * 10 + d

    min_num = 0
    for d in digits_sorted:
        min_num = min_num * 10 + d

    return max_num, min_num, max_num - min_num

# 测试
print(split_digits(52341))     # [5, 2, 3, 4, 1]
print(sort_digits(52341))      # 12345
print(reverse_number(52341))   # 14325
max_n, min_n, diff = max_min_diff(52341)
print(f"{max_n} - {min_n} = {diff}")  # 54321 - 12345 = 41976

方法2:字符串转换法(更简洁)

Python
def split_digits_str(n):
    """用字符串方法拆分数字"""
    return [int(ch) for ch in str(n)]

def sort_digits_str(n):
    """用字符串排序重组"""
    sorted_str = ''.join(sorted(str(n)))
    return int(sorted_str)

def reverse_number_str(n):
    """用字符串反转"""
    return int(str(n)[::-1])

def max_min_diff_str(n):
    """用字符串方法计算最大最小差值"""
    s = str(n)
    max_num = int(''.join(sorted(s, reverse=True)))
    min_num = int(''.join(sorted(s)))
    return max_num, min_num, max_num - min_num

# 测试
print(split_digits_str(52341))    # [5, 2, 3, 4, 1]
print(sort_digits_str(52341))     # 12345
print(reverse_number_str(52341))  # 14325
print(max_min_diff_str(52341))    # (54321, 12345, 41976)

🔑 知识点

知识点 说明
n % 10 取末位数字
n // 10 去掉末位数字
digits.reverse() 列表原地反转,无返回值
sorted(str(n)) 对字符串排序,返回字符列表
''.join(list) 将字符列表拼接为字符串
str(n)[::-1] 字符串反转的惯用写法
int(ch) / str(d) 数字与字符互转

数字拆分过程图解(以 52341 为例):

Text Only
1
2
3
4
5
6
7
n=52341 → 52341 % 10 = 1, digits=[1],   n=5234
n=5234  → 5234 % 10 = 4,  digits=[1,4],  n=523
n=523   → 523 % 10 = 3,   digits=[1,4,3], n=52
n=52    → 52 % 10 = 2,    digits=[1,4,3,2], n=5
n=5     → 5 % 10 = 5,     digits=[1,4,3,2,5], n=0

反转后: digits = [5,2,3,4,1]
📖 拓展
Python
# 拓展1:卡普雷卡尔常数(6174)
def kaprekar_process(n):
    """四位数卡普雷卡尔过程"""
    seen = []
    while n != 6174 and n not in seen:
        seen.append(n)
        digits = [int(ch) for ch in f"{n:04d}"]  # 补零到4位
        desc = int(''.join(sorted(f"{n:04d}", reverse=True)))
        asc = int(''.join(sorted(f"{n:04d}")))
        n = desc - asc
        print(f"{desc} - {asc} = {n}")
    print(f"经过 {len(seen)} 步到达 6174")

kaprekar_process(5234)
# 5432 - 2345 = 3087
# 8730 - 0378 = 8352
# 8532 - 2358 = 6174

# 拓展2:水仙花数(各位数字立方和等于自身)
def narcissistic_numbers():
    """找出所有三位水仙花数"""
    result = []
    for n in range(100, 1000):
        digits = [int(ch) for ch in str(n)]
        if sum(d ** 3 for d in digits) == n:
            result.append(n)
    return result

print(narcissistic_numbers())  # [153, 370, 371, 407]

# 拓展3:数字各位之和
def digit_sum(n):
    """计算各位数字之和"""
    return sum(int(ch) for ch in str(abs(n)))

print(digit_sum(52341))  # 5+2+3+4+1 = 15

📌 记忆要点

  • 数字拆分核心循环:digits.append(n%10) + n//=10,最后 reverse()

  • 字符串方法更简洁:str(n) → 排序/反转 → int() 还原

  • sorted(s, reverse=True) 降序,sorted(s) 升序

  • str(n)[::-1] 是字符串反转的标准写法


第4题:字符串加密与解密

题目: 编写程序,实现两种字符串加密方式,并支持对应的解密。

方法1:基础实现(最直观)

Python
def encrypt_caesar(text, key):
    """凯撒加密:字母后移 key 位"""
    result = ""
    for ch in text:
        if 'a' <= ch <= 'z':
            result += chr((ord(ch) - ord('a') + key) % 26 + ord('a'))
        elif 'A' <= ch <= 'Z':
            result += chr((ord(ch) - ord('A') + key) % 26 + ord('A'))
        else:
            result += ch  # 非字母不变
    return result

def decrypt_caesar(text, key):
    """凯撒解密:字母前移 key 位"""
    return encrypt_caesar(text, -key)

def encrypt_reverse(text):
    """反转加密:反转字符串后每个字符ASCII加1"""
    reversed_text = text[::-1]
    result = ""
    for ch in reversed_text:
        result += chr(ord(ch) + 1)
    return result

def decrypt_reverse(text):
    """反转解密:每个字符ASCII减1后反转"""
    shifted = ""
    for ch in text:
        shifted += chr(ord(ch) - 1)
    return shifted[::-1]

# 测试
print(encrypt_caesar("Hello", 3))    # Khoor
print(decrypt_caesar("Khoor", 3))    # Hello
print(encrypt_reverse("Ab1"))         # 2cB
print(decrypt_reverse("2cB"))         # Ab1

方法2:使用 str.maketrans 和列表推导式

Python
def encrypt_caesar_v2(text, key):
    """使用 maketrans 的凯撒加密"""
    lower = 'abcdefghijklmnopqrstuvwxyz'
    upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    shifted_lower = lower[key % 26:] + lower[:key % 26]
    shifted_upper = upper[key % 26:] + upper[:key % 26]
    table = str.maketrans(lower + upper, shifted_lower + shifted_upper)
    return text.translate(table)

def decrypt_caesar_v2(text, key):
    return encrypt_caesar_v2(text, -key)

def encrypt_reverse_v2(text):
    """使用列表推导式的反转加密"""
    return ''.join(chr(ord(ch) + 1) for ch in text[::-1])

def decrypt_reverse_v2(text):
    """使用列表推导式的反转解密"""
    return ''.join(chr(ord(ch) - 1) for ch in text)[::-1]

# 测试
print(encrypt_caesar_v2("Hello World!", 3))  # Khoor Zruog!
print(decrypt_caesar_v2("Khoor Zruog!", 3))  # Hello World!
print(encrypt_reverse_v2("Ab1"))               # 2cB
print(decrypt_reverse_v2("2cB"))               # Ab1

🔑 知识点

知识点 说明
ord(ch) 获取字符的 ASCII/Unicode 码值
chr(num) 将码值转换为字符
% 26 模运算实现字母循环(Z 后回到 A)
str.maketrans() 创建字符映射表
str.translate() 按映射表转换字符串
凯撒加密公式 chr((ord(ch) - base + key) % 26 + base)
反转加密 先反转字符串,再对每个字符 ASCII 操作

凯撒加密图解(key=3):

Text Only
1
2
3
4
5
6
原文:  A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
密文:  D E F G H I J K L M N O P Q R S T U V W X Y Z A B C

H → K  (H=7, 7+3=10 → K)
e → h  (e=4, 4+3=7  → h)
l → o  (l=11, 11+3=14 → o)

反转加密图解("Ab1"):

Text Only
1
2
3
4
原文: A  b  1
反转: 1  b  A
ASCII+1: 2  c  B
结果: "2cB"
📖 拓展
Python
# 拓展1:暴力破解凯撒密码
def caesar_brute_force(ciphertext):
    """尝试所有26种偏移量"""
    for key in range(26):
        plaintext = encrypt_caesar(ciphertext, -key)
        print(f"key={key:2d}: {plaintext}")

caesar_brute_force("Khoor Zruog!")

# 拓展2:ROT13(固定偏移13的凯撒密码,加密=解密)
def rot13(text):
    """ROT13:加密和解密是同一个操作"""
    return encrypt_caesar(text, 13)

print(rot13("Hello World!"))      # Uryyb Jbeyq!
print(rot13(rot13("Hello World!")))  # Hello World!

# 拓展3:维吉尼亚密码(多表替换)
def vigenere_encrypt(text, keyword):
    """维吉尼亚加密:使用关键词循环移位"""
    result = ""
    key_upper = keyword.upper()
    key_idx = 0
    for ch in text:
        if ch.isalpha():
            shift = ord(key_upper[key_idx % len(key_upper)]) - ord('A')
            if ch.islower():
                result += chr((ord(ch) - ord('a') + shift) % 26 + ord('a'))
            else:
                result += chr((ord(ch) - ord('A') + shift) % 26 + ord('A'))
            key_idx += 1
        else:
            result += ch
    return result

print(vigenere_encrypt("Hello World", "KEY"))  # Rijvs Uyvjn

📌 记忆要点

  • 凯撒加密核心:chr((ord(ch) - base + key) % 26 + base)

  • 解密 = 反向偏移:encrypt(text, -key)

  • % 26 实现字母循环,处理 Z → A 的回绕

  • 反转加密两步:先反转,再 ASCII 操作;解密反序

  • str.maketrans() + str.translate() 是批量字符替换的高效方法


第5题:列表数据筛选与统计

题目: 编写程序,对一组学生成绩数据进行筛选、排序和统计分析。

方法1:基础循环与条件判断(最直观)

Python
# 原始数据
students = [
    ("张三", 85), ("李四", 92), ("王五", 78),
    ("赵六", 95), ("钱七", 60), ("孙八", 88),
    ("周九", 45), ("吴十", 73)
]

# 1. 最高分和最低分
max_student = students[0]
min_student = students[0]
for name, score in students:
    if score > max_student[1]:
        max_student = (name, score)
    if score < min_student[1]:
        min_student = (name, score)
print(f"最高分: {max_student[0]} {max_student[1]}")
print(f"最低分: {min_student[0]} {min_student[1]}")

# 2. 筛选及格学生并按成绩降序排列
passed = [(name, score) for name, score in students if score >= 60]
# 冒泡排序(降序)
for i in range(len(passed)):
    for j in range(len(passed) - 1 - i):
        if passed[j][1] < passed[j + 1][1]:
            passed[j], passed[j + 1] = passed[j + 1], passed[j]
print(f"及格学生(降序): {passed}")

# 3. 平均分与及格率
total = sum(score for _, score in students)
avg = total / len(students)
pass_count = sum(1 for _, score in students if score >= 60)
pass_rate = pass_count / len(students) * 100
print(f"平均分: {avg:.1f}")
print(f"及格率: {pass_rate:.1f}%")

# 4. 等级统计
grades = {"优秀": 0, "良好": 0, "中等": 0, "及格": 0, "不及格": 0}
for _, score in students:
    if score >= 90:   grades["优秀"] += 1
    elif score >= 80: grades["良好"] += 1
    elif score >= 70: grades["中等"] += 1
    elif score >= 60: grades["及格"] += 1
    else:             grades["不及格"] += 1
grade_str = ", ".join(f"{k}{v}人" for k, v in grades.items())
print(f"等级统计: {grade_str}")

方法2:使用内置函数和排序(更简洁)

Python
students = [
    ("张三", 85), ("李四", 92), ("王五", 78),
    ("赵六", 95), ("钱七", 60), ("孙八", 88),
    ("周九", 45), ("吴十", 73)
]

# 1. 最高分和最低分(使用 max/min + key)
max_student = max(students, key=lambda x: x[1])
min_student = min(students, key=lambda x: x[1])
print(f"最高分: {max_student[0]} {max_student[1]}")
print(f"最低分: {min_student[0]} {min_student[1]}")

# 2. 筛选及格学生并排序(sorted + key)
passed = sorted(
    [(n, s) for n, s in students if s >= 60],
    key=lambda x: x[1], reverse=True
)
print(f"及格学生(降序): {passed}")

# 3. 平均分与及格率
scores = [s for _, s in students]
avg = sum(scores) / len(scores)
pass_rate = sum(1 for s in scores if s >= 60) / len(scores) * 100
print(f"平均分: {avg:.1f}")
print(f"及格率: {pass_rate:.1f}%")

# 4. 等级统计(使用函数映射)
def get_grade(score):
    if score >= 90: return "优秀"
    elif score >= 80: return "良好"
    elif score >= 70: return "中等"
    elif score >= 60: return "及格"
    else: return "不及格"

grade_names = ["优秀", "良好", "中等", "及格", "不及格"]
grade_counts = {g: 0 for g in grade_names}
for _, score in students:
    grade_counts[get_grade(score)] += 1
grade_str = ", ".join(f"{g}{grade_counts[g]}人" for g in grade_names)
print(f"等级统计: {grade_str}")

🔑 知识点

知识点 说明
max(lst, key=lambda) 按指定条件取最大值
sorted(lst, key=lambda, reverse=True) 按条件降序排序
列表推导筛选 [x for x in lst if condition]
sum(1 for ... if ...) 统计满足条件的元素个数
sum(scores) / len(scores) 计算平均值
f"{value:.1f}" 保留1位小数格式化输出
多条件分支 if/elif/else 实现等级划分

排序关键参数:

Text Only
1
2
3
4
5
6
7
sorted(iterable, key=lambda, reverse=True/False)

key:     排序依据(函数返回比较值)
reverse: True=降序,False=升序(默认)

例: sorted(students, key=lambda x: x[1], reverse=True)
    按成绩(索引1)降序排列
📖 拓展
Python
# 拓展1:使用 Counter 快速统计
from collections import Counter

students = [
    ("张三", 85), ("李四", 92), ("王五", 78),
    ("赵六", 95), ("钱七", 60), ("孙八", 88),
    ("周九", 45), ("吴十", 73)
]

grade_list = [get_grade(s) for _, s in students]
grade_counter = Counter(grade_list)
for g in ["优秀", "良好", "中等", "及格", "不及格"]:
    print(f"{g}: {grade_counter.get(g, 0)}人")

# 拓展2:成绩分段柱状图(文本版)
def score_histogram(students):
    """用文本绘制成绩分段柱状图"""
    ranges = [(90, 100, '优秀'), (80, 89, '良好'),
              (70, 79, '中等'), (60, 69, '及格'), (0, 59, '不及格')]
    for low, high, label in ranges:
        count = sum(1 for _, s in students if low <= s <= high)
        bar = '█' * count
        print(f"{label:>4} ({low:2d}-{high:3d}): {bar} {count}人")

score_histogram(students)

# 拓展3:成绩排名带同分处理
def rank_scores(students):
    """排名,同分同名次"""
    sorted_stu = sorted(students, key=lambda x: x[1], reverse=True)
    ranks = []
    rank = 1
    for i, (name, score) in enumerate(sorted_stu):
        if i > 0 and score < sorted_stu[i - 1][1]:
            rank = i + 1
        ranks.append((rank, name, score))
    return ranks

for rank, name, score in rank_scores(students):
    print(f"第{rank}名: {name} {score}分")

📌 记忆要点

  • 筛选:列表推导 [x for x in lst if condition]

  • 排序:sorted(lst, key=lambda x: x[1], reverse=True) 按值降序

  • 统计个数:sum(1 for x in lst if condition)Counter

  • 最大/最小:max(lst, key=lambda) / min(lst, key=lambda)

  • 及格率:及格人数 / 总人数 * 100


第6题:斐波那契数列与最大公约数

题目: 编写程序,实现斐波那契数列生成和最大公约数/最小公倍数计算。

方法1:迭代法(最直观)

Python
def fibonacci(n):
    """生成前 n 个斐波那契数(迭代法)"""
    if n <= 0:
        return []
    if n == 1:
        return [1]
    fib = [1, 1]
    for i in range(2, n):
        fib.append(fib[i - 1] + fib[i - 2])
    return fib

def gcd(a, b):
    """辗转相除法求最大公约数"""
    while b != 0:
        a, b = b, a % b
    return a

def lcm(a, b):
    """利用 GCD 求最小公倍数"""
    return a * b // gcd(a, b)

# 测试
print(fibonacci(10))     # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
print(gcd(48, 36))       # 12
print(lcm(48, 36))       # 144

# 斐波那契数列前10项相邻项的GCD
fib = fibonacci(10)
for i in range(len(fib) - 1):
    g = gcd(fib[i], fib[i + 1])
    print(f"gcd({fib[i]}, {fib[i+1]}) = {g}", end="  ")
# gcd(1,1)=1  gcd(1,2)=1  gcd(2,3)=1  gcd(3,5)=1  gcd(5,8)=1  ...
# 斐波那契数列相邻项的GCD始终为1!

方法2:递归法与更相减损术

Python
def fibonacci_recursive(n):
    """递归法生成前 n 个斐波那契数"""
    if n <= 0:
        return []
    def fib(k):
        if k <= 2:
            return 1
        return fib(k - 1) + fib(k - 2)
    return [fib(i) for i in range(1, n + 1)]

def fibonacci_generator(n):
    """生成器方式生成斐波那契数列"""
    a, b = 1, 1
    result = []
    for _ in range(n):
        result.append(a)
        a, b = b, a + b
    return result

def gcd_subtraction(a, b):
    """更相减损术求最大公约数"""
    while a != b:
        if a > b:
            a = a - b
        else:
            b = b - a
    return a

def gcd_recursive(a, b):
    """递归版辗转相除法"""
    if b == 0:
        return a
    return gcd_recursive(b, a % b)

# 测试
print(fibonacci_generator(10))  # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
print(gcd_subtraction(48, 36))  # 12
print(gcd_recursive(48, 36))    # 12

# 验证斐波那契数列相邻项GCD性质
fib = fibonacci_generator(20)
print("\n前20项相邻项GCD:")
for i in range(len(fib) - 1):
    g = gcd(fib[i], fib[i + 1])
    print(f"gcd({fib[i]},{fib[i+1]})={g}", end=" ")
# 全部为1,因为相邻斐波那契数互素

🔑 知识点

知识点 说明
斐波那契定义 F(1)=1, F(2)=1, F(n)=F(n-1)+F(n-2)
迭代法 用循环逐项计算,效率高,推荐使用
递归法 直接翻译数学定义,但效率低(大量重复计算)
a, b = b, a + b Python 同时赋值,无需临时变量
辗转相除法 gcd(a,b) = gcd(b, a%b),直到 b=0
更相减损术 大数减小数,直到两数相等
LCM公式 lcm(a,b) = a * b // gcd(a,b)

辗转相除法图解(gcd(48, 36)):

Text Only
1
2
3
48 ÷ 36 = 1 余 12  → gcd(36, 12)
36 ÷ 12 = 3 余 0   → gcd(12, 0)
余数为0,结果为 12

斐波那契数列前10项:

Text Only
1
2
3
项数:  1  2  3  4  5  6  7   8   9   10
值:    1  1  2  3  5  8  13  21  34  55
规律:  每项 = 前两项之和
📖 拓展
Python
# 拓展1:斐波那契数列的应用——黄金分割
def golden_ratio(n):
    """计算斐波那契数列相邻项的比值,趋近黄金分割"""
    fib = fibonacci(n + 1)
    for i in range(2, len(fib)):
        ratio = fib[i] / fib[i - 1]
        print(f"F({i})/F({i-1}) = {fib[i]}/{fib[i-1]} = {ratio:.6f}")

golden_ratio(15)
# 比值逐渐趋近 1.618034...(黄金分割比)

# 拓展2:判断一个数是否为斐波那契数
def is_fibonacci(n):
    """判断 n 是否为斐波那契数"""
    # 性质:5n²+4 或 5n²-4 之一是完全平方数
    import math
    def is_perfect_square(x):
        s = int(math.sqrt(x))
        return s * s == x
    return is_perfect_square(5 * n * n + 4) or \
           is_perfect_square(5 * n * n - 4)

print(is_fibonacci(55))   # True
print(is_fibonacci(54))   # False

# 拓展3:求多个数的最大公约数
def gcd_multiple(*numbers):
    """求多个数的最大公约数"""
    result = numbers[0]
    for num in numbers[1:]:
        result = gcd(result, num)
    return result

def lcm_multiple(*numbers):
    """求多个数的最小公倍数"""
    result = numbers[0]
    for num in numbers[1:]:
        result = lcm(result, num)
    return result

print(gcd_multiple(12, 18, 24))    # 6
print(lcm_multiple(4, 6, 8))       # 24

📌 记忆要点

  • 斐波那契迭代法:a, b = b, a + b,简洁高效

  • 递归法虽直观但有大量重复计算,实际中不推荐

  • 辗转相除法:while b: a, b = b, a % b,最终 a 即为 GCD

  • LCM = a * b // gcd(a, b),注意先除后乘防溢出

  • 斐波那契数列相邻项互素(GCD 始终为1)


第7题:CSV 文件读取与成绩排名

题目: 编写程序,从 CSV 文件中读取学生成绩,计算总分和平均分,按总分排名后写入新文件。

方法1:基础文件操作(最直观)

Python
def process_grades(input_file, output_file):
    """读取成绩CSV,计算排名,写入结果"""
    # ===== 第一步:读取数据 =====
    students = []
    with open(input_file, 'r', encoding='utf-8') as f:
        header = f.readline().strip()  # 读取表头
        subjects = header.split(',')[1:]  # 科目名列表
        for line in f:
            line = line.strip()
            if not line:
                continue
            parts = line.split(',')
            name = parts[0]
            scores = [int(x) for x in parts[1:]]
            students.append({'name': name, 'scores': scores})

    # ===== 第二步:计算总分和平均分 =====
    for stu in students:
        stu['total'] = sum(stu['scores'])
        stu['avg'] = stu['total'] / len(stu['scores'])

    # ===== 第三步:按总分降序排序 =====
    students.sort(key=lambda x: x['total'], reverse=True)
    for rank, stu in enumerate(students, 1):
        stu['rank'] = rank

    # ===== 第四步:计算课程平均分 =====
    course_avgs = []
    for i, subject in enumerate(subjects):
        scores = [stu['scores'][i] for stu in students]
        avg = sum(scores) / len(scores)
        course_avgs.append((subject, avg))

    # ===== 第五步:写入结果文件 =====
    with open(output_file, 'w', encoding='utf-8') as f:
        # 写入排名表
        f.write("排名,姓名," + ",".join(subjects) + ",总分,平均分\n")
        for stu in students:
            scores_str = ",".join(str(s) for s in stu['scores'])
            f.write(f"{stu['rank']},{stu['name']},{scores_str},"
                    f"{stu['total']},{stu['avg']:.1f}\n")

        # 写入课程平均分
        f.write("\n课程平均分: " +
                ", ".join(f"{subj}{avg:.1f}" for subj, avg in course_avgs) + "\n")

    print(f"处理完成,结果已写入 {output_file}")

# ===== 创建测试文件 =====
def create_test_file(filename):
    with open(filename, 'w', encoding='utf-8') as f:
        f.write("姓名,语文,数学,英语\n")
        f.write("张三,85,92,78\n")
        f.write("李四,90,88,95\n")
        f.write("王五,72,80,76\n")
        f.write("赵六,88,95,82\n")

create_test_file("scores.csv")
process_grades("scores.csv", "rank.csv")

# 查看输出文件
with open("rank.csv", 'r', encoding='utf-8') as f:
    print(f.read())

输出文件内容:

Text Only
1
2
3
4
5
6
7
排名,姓名,语文,数学,英语,总分,平均分
1,李四,90,88,95,273,91.0
2,赵六,88,95,82,265,88.3
3,张三,85,92,78,255,85.0
4,王五,72,80,76,228,76.0

课程平均分: 语文83.8, 数学88.8, 英语82.8

方法2:使用 csv 模块(更健壮)

Python
import csv

def process_grades_csv(input_file, output_file):
    """使用 csv 模块处理成绩文件"""
    # 读取数据
    students = []
    with open(input_file, 'r', encoding='utf-8', newline='') as f:
        reader = csv.reader(f)
        header = next(reader)        # 读取表头
        subjects = header[1:]         # 科目名
        for row in reader:
            if not row:
                continue
            name = row[0]
            scores = [int(x) for x in row[1:]]
            students.append({
                'name': name,
                'scores': scores,
                'total': sum(scores),
                'avg': sum(scores) / len(scores)
            })

    # 按总分降序排序
    students.sort(key=lambda x: x['total'], reverse=True)
    for rank, stu in enumerate(students, 1):
        stu['rank'] = rank

    # 课程平均分
    course_avgs = []
    for i, subject in enumerate(subjects):
        scores = [stu['scores'][i] for stu in students]
        course_avgs.append(sum(scores) / len(scores))

    # 写入 CSV 结果
    with open(output_file, 'w', encoding='utf-8', newline='') as f:
        writer = csv.writer(f)
        # 表头
        writer.writerow(['排名', '姓名'] + subjects + ['总分', '平均分'])
        # 数据行
        for stu in students:
            writer.writerow([stu['rank'], stu['name']] +
                            stu['scores'] +
                            [stu['total'], f"{stu['avg']:.1f}"])
        # 课程平均分
        writer.writerow([])
        avg_str = "课程平均分: " + ", ".join(
            f"{subjects[i]}{course_avgs[i]:.1f}"
            for i in range(len(subjects))
        )
        writer.writerow([avg_str])

    print(f"处理完成,结果已写入 {output_file}")

# 测试
process_grades_csv("scores.csv", "rank_v2.csv")

🔑 知识点

知识点 说明
with open() 上下文管理器,自动关闭文件
encoding='utf-8' 中文文件必须指定编码
f.readline() 读取一行(含换行符),常用于跳过表头
line.strip().split(',') 去除空白后按逗号分割 CSV 行
csv.reader() csv 模块读取,正确处理引号内的逗号
csv.writer() csv 模块写入,自动处理特殊字符
sorted(lst, key=lambda, reverse) 按指定字段降序排序
enumerate(lst, 1) 带起始编号的遍历,用于生成排名

CSV 文件处理流程:

Text Only
1
2
3
读取文件 → 解析CSV行 → 计算统计量 → 排序 → 写入结果
   ↓            ↓            ↓          ↓         ↓
open()    split(',')   sum/avg    sort()   write()
📖 拓展
Python
# 拓展1:处理不确定科目数的成绩文件
def process_flexible(input_file, output_file):
    """自适应科目数的成绩处理"""
    with open(input_file, 'r', encoding='utf-8') as f:
        lines = [line.strip() for line in f if line.strip()]

    header = lines[0].split(',')
    subjects = header[1:]
    students = []
    for line in lines[1:]:
        parts = line.split(',')
        name = parts[0]
        scores = [int(x) for x in parts[1:]]
        students.append({
            'name': name, 'scores': scores,
            'total': sum(scores),
            'avg': sum(scores) / len(scores)
        })
    students.sort(key=lambda x: x['total'], reverse=True)
    return students, subjects

# 拓展2:成绩等级划分
def assign_grades(students):
    """为每位学生添加等级"""
    for stu in students:
        avg = stu['avg']
        if avg >= 90:   stu['grade'] = 'A'
        elif avg >= 80: stu['grade'] = 'B'
        elif avg >= 70: stu['grade'] = 'C'
        elif avg >= 60: stu['grade'] = 'D'
        else:           stu['grade'] = 'F'
    return students

# 拓展3:按多字段排序(总分相同时按语文分排序)
def multi_sort(students):
    """总分相同时按语文成绩排序"""
    students.sort(key=lambda x: (x['total'], x['scores'][0]),
                  reverse=True)
    return students

# 拓展4:读取文件时的异常处理
def safe_read_csv(filename):
    """带异常处理的CSV读取"""
    try:
        with open(filename, 'r', encoding='utf-8') as f:
            content = f.read()
        if not content.strip():
            print("文件为空")
            return []
        return content.splitlines()
    except FileNotFoundError:
        print(f"文件 {filename} 不存在")
        return []
    except PermissionError:
        print(f"无权限读取文件 {filename}")
        return []

📌 记忆要点

  • 文件操作三步:with open() → 读写 → 自动关闭

  • 读 CSV:跳过表头(readline()next(reader)),逐行解析

  • 写 CSV:csv.writer() 比手动拼接更健壮

  • 排序加排名:先 sort()enumerate(students, 1)

  • 中文文件务必 encoding='utf-8',写 CSV 加 newline=''


第8题:图案打印

题目: 编写程序,根据输入的行数 n,打印多种对称图案。

方法1:循环拼接法(最直观)

Python
def print_triangle(n):
    """打印 n 行直角三角形"""
    for i in range(1, n + 1):
        print('*' * i)

def print_diamond(n):
    """打印 2n-1 行实心菱形"""
    # 上半部分(含中间行)
    for i in range(1, n + 1):
        spaces = ' ' * (n - i)
        stars = '*' * (2 * i - 1)
        print(spaces + stars)
    # 下半部分
    for i in range(n - 1, 0, -1):
        spaces = ' ' * (n - i)
        stars = '*' * (2 * i - 1)
        print(spaces + stars)

def print_hollow_diamond(n):
    """打印 2n-1 行空心菱形"""
    # 上半部分(含中间行)
    for i in range(1, n + 1):
        spaces = ' ' * (n - i)
        if i == 1:
            print(spaces + '*')
        else:
            inner_spaces = ' ' * (2 * i - 3)
            print(spaces + '*' + inner_spaces + '*')
    # 下半部分
    for i in range(n - 1, 0, -1):
        spaces = ' ' * (n - i)
        if i == 1:
            print(spaces + '*')
        else:
            inner_spaces = ' ' * (2 * i - 3)
            print(spaces + '*' + inner_spaces + '*')

# 测试
print("=== 直角三角形 ===")
print_triangle(4)
print("\n=== 实心菱形 ===")
print_diamond(3)
print("\n=== 空心菱形 ===")
print_hollow_diamond(3)

输出:

Text Only
=== 直角三角形 ===
*
**
***
****

=== 实心菱形 ===
  *
 ***
*****
 ***
  *

=== 空心菱形 ===
  *
 * *
*   *
 * *
  *

方法2:使用 center 方法(更简洁)

Python
def print_triangle_v2(n):
    """左对齐直角三角形"""
    for i in range(1, n + 1):
        print('*' * i)

def print_diamond_v2(n):
    """使用 center 打印实心菱形"""
    width = 2 * n - 1  # 最宽行的宽度
    # 上半部分
    for i in range(1, n + 1):
        line = '*' * (2 * i - 1)
        print(line.center(width))
    # 下半部分
    for i in range(n - 1, 0, -1):
        line = '*' * (2 * i - 1)
        print(line.center(width))

def print_hollow_diamond_v2(n):
    """使用 center 打印空心菱形"""
    width = 2 * n - 1
    # 上半部分
    for i in range(1, n + 1):
        if i == 1:
            print('*'.center(width))
        else:
            # 内部空格数 = 2i - 3
            line = '*' + ' ' * (2 * i - 3) + '*'
            print(line.center(width))
    # 下半部分
    for i in range(n - 1, 0, -1):
        if i == 1:
            print('*'.center(width))
        else:
            line = '*' + ' ' * (2 * i - 3) + '*'
            print(line.center(width))

# 测试
print_diamond_v2(4)
#    *
#   ***
#  *****
# *******
#  *****
#   ***
#    *

print_hollow_diamond_v2(4)
#    *
#   * *
#  *   *
# *     *
#  *   *
#   * *
#    *

🔑 知识点

知识点 说明
'*' * n 字符串重复,生成 n 个星号
' ' * n 生成 n 个空格
str.center(width) 字符串居中对齐,两侧填充空格
range(n-1, 0, -1) 递减循环,从 n-1 到 1
菱形行数 2n - 1 行(n 行上半 + n-1 行下半)
第 i 行星号数 实心:2i-1;空心:2个(首尾行1个)
第 i 行前导空格 n - i 个

菱形图案规律图解(n=3):

Text Only
行号i  前导空格  星号数  内部空格(空心)
  1      2        1       0(顶点)
  2      1        3       1
  3      0        5       3(最宽行)
  2      1        3       1
  1      2        1       0(底点)

规律:
  前导空格 = n - i
  星号数   = 2 * i - 1
  内部空格 = 2 * i - 3(i>=2时)
📖 拓展
Python
# 拓展1:等腰三角形
def print_isosceles_triangle(n):
    """打印 n 行等腰三角形"""
    for i in range(1, n + 1):
        spaces = ' ' * (n - i)
        stars = '*' * (2 * i - 1)
        print(spaces + stars)

print_isosceles_triangle(4)
#    *
#   ***
#  *****
# *******

# 拓展2:数字三角形
def print_number_triangle(n):
    """打印数字三角形"""
    for i in range(1, n + 1):
        for j in range(1, i + 1):
            print(j, end=' ')
        print()

print_number_triangle(5)
# 1
# 1 2
# 1 2 3
# 1 2 3 4
# 1 2 3 4 5

# 拓展3:乘法口诀表
def print_multiplication_table():
    """打印九九乘法表"""
    for i in range(1, 10):
        for j in range(1, i + 1):
            print(f"{j}×{i}={i*j:2d}", end=' ')
        print()

print_multiplication_table()
# 1×1= 1
# 1×2= 2  2×2= 4
# 1×3= 3  2×3= 6  3×3= 9
# ...

# 拓展4:沙漏图案
def print_hourglass(n):
    """打印沙漏图案(2n-1行)"""
    width = 2 * n - 1
    # 上半部分(倒三角)
    for i in range(n, 0, -1):
        line = '*' * (2 * i - 1)
        print(line.center(width))
    # 下半部分(正三角,不含顶点)
    for i in range(2, n + 1):
        line = '*' * (2 * i - 1)
        print(line.center(width))

print_hourglass(3)
# *****
#  ***
#   *
#  ***
# *****

📌 记忆要点

  • 图案打印核心:分析每行的前导空格数星号数与行号的关系

  • 菱形规律:前导空格 = n - i,星号数 = 2 * i - 1

  • 字符串乘法:'*' * n 生成 n 个星号,' ' * n 生成 n 个空格

  • str.center(width) 可简化居中对齐

  • 菱形分两半:上半 range(1, n+1) 递增,下半 range(n-1, 0, -1) 递减

  • 空心菱形:首尾行 1 个星号,中间行 2 个星号 + 内部空格