把变量想成贴了名字的储物箱:age = 10 就是往叫 age 的箱子放数字 10。
箱子有规矩:名字不能以数字开头(不能叫 2age),不能用关键字(不能叫 if),再放新东西旧东西就被换掉。
依据《CCF 编程能力等级认证 C++&Python 认证标准》整理。GESP 由中国计算机学会主办,Python 编程认证共一至八级,从编程入门到图论与算法优化逐级递进。每个知识点均配有详细讲解、Python 代码示例、易错点提示,并配模拟题讲解;难懂处附适合小学生、初中生的生活化例子。
《CCF 编程能力等级认证 C++&Python 认证标准》由中国计算机学会(CCF)制定,认证划分为一至八级,' '为学习者提供编程能力水平的证明。考试采用上机考试,题型为单选题(15 道 × 2 分)+ 判断题(10 道 × 2 分)+ 编程题(2 道 × 25 分),' '1-4 级考试时间 120 分钟,5-8 级 180 分钟。
八级内容呈现明显的螺旋递进:基础语法 → 函数与算法 → 数据结构与搜索 → 动态规划与图论 → 综合与优化。
Python 常用开发环境有 IDLE(自带)、PyCharm、Thonny、VS Code 等。GESP 一级要求会用环境新建文件、编辑、保存、运行、调试。
交互模式(>>> 逐行执行)和 脚本模式(写完整 .py 文件运行)。Python 文件后缀是 .py。IndentationError;② 注释用 #。# 单行注释、"""...""" 多行注释。3.14、"hello");name = "小明" # 变量:字符串
age = 10 # 变量:整数
score = 95.5 # 变量:小数
print(name, age, score)把变量想成贴了名字的储物箱:age = 10 就是往叫 age 的箱子放数字 10。
箱子有规矩:名字不能以数字开头(不能叫 2age),不能用关键字(不能叫 if),再放新东西旧东西就被换掉。
| 类型 | 英文 | 例子 | 说明 | |||
|---|---|---|---|---|---|---|
| 整 | 数 | |||||
| i | n | t | ||||
| 1 | 0 | 、 | - | 3 | 、 | 0 |
| 没 | 有 | 小 | 数 | 点 | 的 | 数 |
a = 10 # int
b = 3.14 # float
c = "你好" # str
d = True # bool
print(type(a)) # <class 'int'>
print(type(c)) # <class 'str'>True/False 首字母大写;③ type() 可查看数据类型。name = input("请输入名字:") # 输入(返回字符串)
print("你好,", name) # 输出
age = int(input("年龄:")) # 要算数先 int()| 类别 | 符号 | 例子 | 结果 | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| 算 | 术 | ||||||||||
| + | - | * | / | % | |||||||
| 7 | / | / | 2 | 、 | 7 | % | 2 | ||||
| 3 | 、 | 1 |
input() 像邮递员:只会送来写满字的纸条。纸条上的"12"只是文字符号,要算数得先拿 int() 翻译机变成真正的数字。
不然 "12" + "5" 变成 "125"(拼接),而不是 17!口诀:要算数,先 int()。
input() 永远返回字符串;② // 整除、% 取余;③ and=并且、or=或者、not=非。# 顺序:从上到下
a = int(input()); b = int(input())
print(a + b)
# 分支
if a >= 60:
print("及格")
else:
print("不及格")
# 循环
s = 0
for i in range(1, 101):
s += i
print(s) # 5050顺序 = 按菜谱一步一步做;分支 = 到了岔路口看条件选一条(if/else);循环 = 体育课跑圈,跑完规定的圈数(for)或跑到下课(while)。
口诀:顺序照着走、分支看条件、循环重复做。
range(1, 101) 是 1~100(不含 101);③ 循环里忘记更新条件会死循环。import turtle # 导入 turtle 模块
t = turtle.Turtle() # 创建小乌龟
t.forward(100) # 前进 100 步
t.left(90) # 左转 90 度
t.forward(100)
turtle.done()| 指令 | 作用 | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| f | o | r | w | a | r | d | ( | n | ) | / | f | d | ( | n | ) |
| 前 | 进 | n |
把 turtle 想成一只跟着命令走的小乌龟:你说"前进 100"它就前进,说"左转 90"它就拐弯——每一条命令就像你牵着的绳子。
抬笔(penup)就像把笔收起来走路不留痕迹,落笔(pendown)再画。
import turtle;② 画完用 turtle.done() 保持窗口;③ 角度单位是度,不是步数。以下例题贴合 GESP 一级考点(环境、变量、数据类型、运算符、结构、turtle)设计:
int("123") + 1 的结果是?for i in range(5): 循环体会执行几次?n = int(input())
if n % 2 == 0:
print("偶数")
else:
print("奇数")用 n % 2:余 0 是偶数,余 1 是奇数。import turtle
t = turtle.Turtle()
for i in range(4):
t.forward(100)
t.left(90)
turtle.done()正方形 = 前进 100、左转 90° 重复 4 次。| 存储器 | 特点 | 用途 | |||||||
|---|---|---|---|---|---|---|---|---|---|
| R | A | M | 内 | 存 | |||||
| 断 | 电 | 丢 | 失 | 、 | 速 | 度 | 快 | ||
| 正 | 在 | 运 | 行 | 的 | 程 | 序 | 和 | 数 | 据 |
把存储器想成你的学习工具:RAM 是书桌(写作业时摊开的本子,放学收走就没了=断电丢失);ROM 是保险箱(里面放着不会变的说明书=开机程序);Cache 是手边的速记本(最常用公式抄在上面,拿起来最快)。
| 语言 | 特点 | 例子 | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 机 | 器 | 语 | 言 | ||||||||||
| 二 | 进 | 制 | 0 | / | 1 | , | 电 | 脑 | 直 | 接 | 执 | 行 | |
| 0 | 1 | 0 | 0 | 1 | 0 | 1 | 1 |
流程图用图形描述算法步骤:圆角矩形=开始/结束、平行四边形=输入输出、矩形=处理、菱形=判断、箭头=流程方向。
ASCII 用数字表示字符,是最基础的字符编码。需要记住几个关键值:
| 字符 | ASCII 码 |
|---|---|
| 空 | 格 |
| 3 | 2 |
print(ord("A")) # 65(字符转编码)
print(chr(65)) # 'A'(编码转字符)
# 小写 = 大写 + 32:'a' = 65 + 32 = 97
print(ord("a") - ord("A")) # 32ord() 字符→数字,chr() 数字→字符;② 数字'0'的编码是 48,字母'A'是 65,'a'是 97;③ 小写字母比大写字母大 32。x = int("123") # 字符串→整数
y = float("3.5") # →小数
s = str(100) # 整数→字符串
n = int(3.99) # 3(截断,不是四舍五入)
print(round(3.6)) # 4(四舍五入)
# 隐式转换:int 和小数运算自动变成小数
print(3 + 0.5) # 3.5int("12.5") 会报错(不是整数格式);② int(3.99) 是截断成 3;③ 字符和数字通过 ord/chr 互相转换。score = int(input())
if score >= 90:
print("优秀")
elif score >= 80:
print("良好")
elif score >= 60:
print("及格")
else:
print("不及格")for i in range(1, 6): # 外层管行
for j in range(1, i + 1): # 内层管列
print("*", end="")
print() # 换行
# 输出直角三角形import math
abs(-5) # 5 绝对值
max(3, 7, 2) # 7 最大值
min(3, 7, 2) # 2 最小值
round(3.6) # 4 四舍五入
math.sqrt(25) # 5.0 平方根
pow(2, 10) # 1024 乘方
# 随机数
import random
random.randint(1, 6) # 1~6 随机整数(掷骰子)math.sqrt,需先 import math;② random.randint(a, b) 包含两端;③ round() 四舍五入。int(3.99) 的结果是?for i in range(1, 10):
for j in range(1, i + 1):
print(f"{j}*{i}={i*j}", end="\t")
print()外层 i 是乘数,内层 j 从 1 到 i。计算机用二进制存整数,负数有原码、反码、补码三种表示:
| 编码 | 正数 | 负数 | 说明 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 原 | 码 | ||||||||||||
| 本 | 身 | ||||||||||||
| 符 | 号 | 位 | 1 | + | 绝 | 对 | 值 | ||||||
| 符 | 号 | 位 | 最 | 左 | 边 | : | 0 | 正 | 1 | 负 |
例:8 位二进制表示 -3:原码 10000011,反码 11111100,补码 11111101。
~x = -x - 1(按位取反)。| 进制 | 基数 | 数字 | 例子 | ||||||
|---|---|---|---|---|---|---|---|---|---|
| 二 | 进 | 制 | |||||||
| 2 | |||||||||
| 0 | 1 | ||||||||
| 1 | 0 | 1 | 0 | ₂ | = | 1 | 0 |
n = 13
s = ""
while n > 0:
s = str(n % 2) + s # 余数往前拼
n //= 2
print(s) # 1101
# Python 内置
print(bin(13)) # 0b1101
print(hex(255)) # 0xff
print(int("1101", 2)) # 13把二进制想成4 盏灯(亮=1 灭=0),分量从左到右是 8、4、2、1:想表示 13 就亮"8+4+1"三盏 → 1101。电脑里所有数据都是灯的亮灭!
bin/oct/hex 输出带前缀。| 符号 | 含义 | 例子 | 结果 | |
|---|---|---|---|---|
| & | ||||
| 按 | 位 | 与 | ||
| 5 | & | 3 | ||
| 1 |
n = 7
print(n & 1) # 1 → 奇数(判断奇偶)
print(n << 1) # 14(×2)
print(n >> 1) # 3(÷2)
a, b = 5, 3
a ^= b; b ^= a; a ^= b # 交换两数(异或技巧)& 1 判奇偶;② 左移一位 = ×2、右移一位 = ÷2;③ 位运算优先级低,判断时要加括号 (n & 1)。算法就是解决问题的一步步明确步骤。三种描述方式:
| 类型 | 符号 | 特点 | 例子 | |||||
|---|---|---|---|---|---|---|---|---|
| 列 | 表 | l | i | s | t | |||
| [ | ] | |||||||
| 有 | 序 | 、 | 可 | 改 | ||||
| [ | 1 | , | 2 | , | 3 | ] |
lst = [3, 1, 2]
lst.append(5) # 末尾加
lst.sort() # 排序
lst[0] # 第一个元素
# 列表解析(推导式)
squares = [x * x for x in range(5)] # [0,1,4,9,16]
even = [x for x in range(10) if x % 2 == 0] # 偶数
d = {"name": "小明", "age": 10}
d["name"] # "小明"
s = {1, 2, 2, 3} # {1, 2, 3}(去重)列表=一排编号储物柜(按位置取);字典=通讯录(按名字找电话);集合=布袋(重复的东西只留一个);列表解析=加工厂流水线(一批原料一次加工成产品)。
[表达式 for 变量 in 序列 if 条件]。| 函数 | 作用 | 例子 | 结果 | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| u | p | p | e | r | ( | ) | / | l | o | w | e | r | ( | ) |
| 大 | 小 | 写 | 转 | 换 | ||||||||||
| " | H | i | " | . | l | o | w | e | r | ( | ) | |||
| " | h | i | " |
s = "Python Programming"
print(s.upper()) # PYTHON PROGRAMMING
print(s.split(" ")) # ['Python', 'Programming']
print(s[0:6]) # 'Python'(切片)split 按分隔符拆成列表、join 反向拼回。# 找 100~999 的水仙花数
for n in range(100, 1000):
a = n // 100
b = n // 10 % 10
c = n % 10
if a**3 + b**3 + c**3 == n:
print(n, end=" ") # 153 370 371 407把枚举想成钥匙不见了,挨个抽屉翻:从第一个翻到最后一个,不重不漏,翻到就验证。循环是"挨个抽屉",if 是"看看是不是钥匙"。
# 模拟:每天存钱,第 1 天 1 元、第 2 天 2 元……n 天后共多少
n = 10
total = 0
for day in range(1, n + 1):
total += day
print(total) # 55把模拟法想成照着说明书一步步做实验:说明书写"第一步加 1 滴,第二步加 2 滴…",你就一步一步照做。题目怎么说,代码就怎么写,别自作聪明跳步。
[x for x in range(6) if x % 2 == 1] 的结果是?for n in range(100, 1000):
if n // 100 == n % 10:
print(n)三位数回文:百位 == 个位。def add(a, b): # a、b 是形参
return a + b
result = add(3, 5) # 3、5 是实参
print(result) # 8def f(x, n=2):。把函数想成菜谱:写好一次随时照着做。形参=菜谱写的"放几个蛋",实参=你实际放 3 个蛋,return=端上桌的菜。一次写好,反复使用!
return;② return 之后的代码不执行;③ 函数要先定义再调用。x = 10 # 全局变量
def f():
x = 20 # 局部变量(函数内新造一个)
print(x) # 20
f()
print(x) # 10(外面没变)count = 0
def add():
global count # 声明要用全局的 count
count += 1
add(); add()
print(count) # 2def change(lst):
lst.append(99) # 列表可变,外面也会变
a = [1, 2]
change(a)
print(a) # [1, 2, 99]global 声明;③ 列表/字典传引用,改了影响外面。# 列表里套字典(学生表)
students = [
{"name": "小明", "scores": [90, 85]},
{"name": "小红", "scores": [88, 95]},
]
print(students[0]["name"]) # 小明
print(students[1]["scores"][0]) # 88
# 字典里套列表
scores = {"math": [80, 90], "chinese": [85, 92]}
for k, v in scores.items():
print(k, sum(v) / len(v))for k, v in d.items() 遍历字典;③ 二维列表 a[i][j] 表示第 i 行第 j 列。从已知的初始项出发,用循环从前往后一步步推出后面的项。
# 斐波那契:f(1)=1, f(2)=1, f(n)=f(n-1)+f(n-2)
n = 10
f = [0] * (n + 1)
f[1] = f[2] = 1
for i in range(3, n + 1):
f[i] = f[i - 1] + f[i - 2]
print(f[n]) # 55到第 n 级台阶,只能从 n-1 走 1 步或从 n-2 走 2 步,所以 f(n)=f(n-1)+f(n-2)。先算小的,一步步推大的,就是递推!
def bubble(a):
n = len(a)
for i in range(n - 1):
for j in range(n - 1 - i):
if a[j] > a[j + 1]:
a[j], a[j + 1] = a[j + 1], a[j]
return adef insert_sort(a):
for i in range(1, len(a)):
key = a[i]; j = i - 1
while j >= 0 and a[j] > key:
a[j + 1] = a[j]; j -= 1
a[j + 1] = key
return a
def select_sort(a):
for i in range(len(a) - 1):
mn = i
for j in range(i + 1, len(a)):
if a[j] < a[mn]: mn = j
a[i], a[mn] = a[mn], a[i]
return a稳定排序:相等元素排序后相对顺序不变。冒泡、插入稳定;选择不稳定。
冒泡=相邻比个子高的往后挪,一轮沉底一个;选择=每轮挑最矮的站前面;插入=打扑克抓一张插到已排好牌中合适位置。
时间复杂度描述数据规模 n 变大时,运算次数增长的快慢。
| 代码结构 | 复杂度 | 例 | ||
|---|---|---|---|---|
| 普 | 通 | 语 | 句 | |
| O | ( | 1 | ) | |
| a | = | 1 |
# 写文件
with open("out.txt", "w", encoding="utf-8") as f:
f.write("第一行\n")
# 追加
with open("out.txt", "a", encoding="utf-8") as f:
f.write("追加内容\n")
# 读文件
with open("out.txt", "r", encoding="utf-8") as f:
for line in f:
print(line.strip())try:
n = int(input("请输入整数:"))
print(100 // n)
except ValueError:
print("输入的不是整数!")
except ZeroDivisionError:
print("不能除以 0!")with open 自动关闭文件;③ try 里出错会跳到 except,程序不崩溃。f=[0]*(n+1); f[1]=f[2]=1 for i in range(3,n+1): f[i]=f[i-1]+f[i-2] print(f[n])从 f[1]、f[2] 出发循环递推。
with open("a.txt") as f:
total = sum(int(line.strip()) for line in f)
print(total)逐行读取、转 int、累加。def is_prime(n):
if n < 2: return False
i = 2
while i * i <= n:
if n % i == 0: return False
i += 1
return Truedef gcd(a, b): # 辗转相除法(欧几里得)
while b:
a, b = b, a % b
return a
def lcm(a, b):
return a * b // gcd(a, b)7 % 3 = 1);(a+b) % m = (a%m + b%m) % m;要铺 24×36 的墙,最大公约数就是能同时整除两边的最大的砖:12。辗转相除法就像大砖切小砖——36 切 24 剩 12,24 再切 12 刚好,答案 12。
math.gcd。| 复杂度 | n=10⁶ 时 | 典型算法 | |
|---|---|---|---|
| O | ( | 1 | ) |
| 瞬 | 间 | ||
| 取 | 下 | 标 |
def binary_search(a, x):
l, r = 0, len(a) - 1
while l <= r:
mid = (l + r) // 2
if a[mid] == x: return mid
elif a[mid] < x: l = mid + 1
else: r = mid - 1
return -1# 例:把 n 根长度不一的绳子切成 m 段,求每段最长能多长
def ok(mid, a, m):
return sum(x // mid for x in a) >= m
n, m = 3, 4
a = [10, 15, 7] # 绳子长度
l, r = 1, max(a)
while l <= r:
mid = (l + r) // 2
if ok(mid, a, m): l = mid + 1
else: r = mid - 1
print(r) # 最长能切 5猜字典里某个字在第几页:翻到中间,比目标大就往左半本找,小就往右半本找,每次都砍掉一半——这就是二分。100 万个数最多 20 次就找到!
mid=(l+r)//2;③ 二分答案:先判断"答案够不够大"再收窄区间。def fact(n):
if n <= 1: return 1 # 终止条件(非常重要)
return n * fact(n - 1) # 递归调用from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n <= 2: return 1
return fib(n - 1) + fib(n - 2)
print(fib(50)) # 12586269025(很快)递归就像俄罗斯套娃:打开大娃得到小娃,再打开小娃得到更小的……直到最小的(终止条件),再一层层带回答案。先一路拆到底,再一路算上来。
def merge_sort(a):
if len(a) <= 1: return a
m = len(a) // 2
L = merge_sort(a[:m]); R = merge_sort(a[m:])
i = j = 0; res = []
while i < len(L) and j < len(R):
if L[i] < R[j]: res.append(L[i]); i += 1
else: res.append(R[j]); j += 1
return res + L[i:] + R[j:]def quick_sort(a):
if len(a) <= 1: return a
p = a[0]
less = [x for x in a[1:] if x <= p]
more = [x for x in a[1:] if x > p]
return quick_sort(less) + [p] + quick_sort(more)归并=先把全班分成两组各自排好,再把两组按顺序合并成一队;快排=随便叫一个同学当"基准",矮的站左边高的站右边,两边再各自排——分而治之!
每一步都选当前看起来最优的选择,最终得到全局最优。贪心要满足最优子结构(局部最优能推出全局最优)。
# 例:硬币找零(面额 1/5/10/20/50,求最少硬币数)
coins = [50, 20, 10, 5, 1]
amount = 78
count = 0
for c in coins:
count += amount // c
amount %= c
print(count) # 5(50+20+5+1+1+1=6? 实际 78=50+20+5+1+1+1)上例 78 = 50+20+5+1+1+1,共 6 枚。贪心每次先用大面额,是最优的。
把贪心想成每次从篮子里挑最大的苹果:每次都选当前最好,凑到一起往往就是最好的一篮。但要注意:有些问题"每次挑最大的"反而错,要先验证最优子结构!
a.sort()
l,r=0,len(a)-1
while l<=r:
m=(l+r)//2
if a[m]==x: print("YES"); break
elif a[m]<x: l=m+1
else: r=m-1
else: print("NO")先排序再二分。i=2; ok=True
while i*i<=n:
if n%i==0: ok=False; break
i+=1
print("YES" if ok and n>1 else "NO")只需试到 √n。class Node:
def __init__(self, v):
self.v = v; self.left = None; self.right = None
def preorder(r): # 前序:根-左-右
if not r: return
print(r.v, end=" "); preorder(r.left); preorder(r.right)
def inorder(r): # 中序:左-根-右
if not r: return
inorder(r.left); print(r.v, end=" "); inorder(r.right)
def postorder(r): # 后序:左-右-根
if not r: return
postorder(r.left); postorder(r.right); print(r.v, end=" ")把树想成族谱:爷爷是根,下面分爸爸、叔叔(孩子),再往下孙子。前序=先记自己再往下记(根左右),中序=先左再自己再右,后序=先孩子最后自己。
给定一组权值(出现频率),构造带权路径长度最小的二叉树。构造方法:每次选两个最小的合并。
左 0 右 1 给每个叶子标路径,频率越高的字符路径越短。特点是前缀编码(任何编码都不是另一个的前缀),可无歧义解码。
除最后一层外都填满,最后一层结点靠左排列。完全二叉树可用数组存储:下标 i 的左孩子 2i、右孩子 2i+1、父亲 i//2。
def insert(root, x):
if root is None: return Node(x)
if x < root.v: root.left = insert(root.left, x)
else: root.right = insert(root.right, x)
return root
# 中序遍历 BST = 从小到大输出二叉排序树=图书馆书架:比编号小的放左边,大的放右边。中序遍历就是从左到右把书按编号排好——插入时一路比较,位置合适就停下。
def dfs(x):
if 越界 or 访问过: return
visited[x] = True
print(x, end=" ")
for nxt in 邻居[x]:
dfs(nxt)DFS 像走进迷宫:一条路走到黑,走不通再回头换一条。
DFS=迷宫探险家一条道走到黑,撞墙就回头(回溯)走另一条,走过的路做记号(visited)防止绕圈。
from collections import deque
def bfs(start):
q = deque([start])
visited = {start}
while q:
x = q.popleft()
print(x, end=" ")
for nxt in 邻居[x]:
if nxt not in visited:
visited.add(nxt); q.append(nxt)BFS=往池塘扔石子,水波一圈圈向外扩散:先到的地方离起点最近。用队列(先来先出)实现,先到的先扩展。找最短步数最合适。
n = 10
dp = [0] * (n + 1)
dp[0] = 1
for i in range(1, n + 1):
dp[i] = dp[i - 1] + (dp[i - 2] if i >= 2 else 0)
print(dp[n]) # 89# 背包容量 W,物品重量 w、价值 v,求最大价值
W, n = 10, 3
w = [0, 3, 4, 5]; v = [0, 4, 5, 6]
dp = [0] * (W + 1)
for i in range(1, n + 1):
for j in range(W, w[i] - 1, -1): # 倒序!0-1 背包
dp[j] = max(dp[j], dp[j - w[i]] + v[i])
print(dp[W]) # 100-1 背包=带 10kg 的箱子出门,每个物品只能带一个或不带,怎么装最值钱?dp[j]=箱子容量 j 时能装的最大价值,逐个物品更新。倒序循环保证每个物品只用一次!
class Dog:
def __init__(self, name, age): # 构造方法
self.name = name # 属性
self.age = age
def bark(self): # 方法
print(self.name, "汪汪!")
d = Dog("旺财", 3)
d.bark() # 旺财 汪汪!类=做饼干的模具(模板),对象=用模具压出的每一块饼干。__init__=给每块饼干印上不同花纹。继承=大模具分出小模具,多态=同样的模具印出不同形状。
self 代表对象本身,方法都要有它;② 类首字母大写是习惯;③ 三大特性:封装、继承、多态。from collections import deque
s = deque() # 用双端队列当栈
s.append(1); s.append(2)
print(s.pop()) # 2(后进先出)q = deque()
q.append(1); q.append(2)
print(q.popleft()) # 1(先进先出)循环队列:用数组实现时,队尾到头再绕回队首,解决假溢出。
栈=食堂叠盘子:后放的先拿(后进先出);队列=排队打饭:先来的先走(先进先出)。
collections.deque 实现两者。q=deque([(sx,sy,0)])
while q:
x,y,step=q.popleft()
if (x,y)==(tx,ty): print(step); break
for dx,dy in [(1,0),(-1,0),(0,1),(0,-1)]:
nx,ny=x+dx,y+dy
if 在界内且可走且未访问:
标记访问; q.append((nx,ny,step+1))每步记录步数,第一次到达终点的步数即最短。class Student:
def __init__(self, name, score):
self.name=name; self.score=score
def show(self):
print(self.name, self.score)构造方法存属性,方法输出。import math
math.sin(math.pi / 2) # 1.0 正弦(弧度)
math.cos(0) # 1.0 余弦
math.log10(1000) # 3.0 以 10 为底的对数
math.log2(8) # 3.0 以 2 为底
math.exp(1) # e ≈ 2.718
math.pow(2, 10) # 1024.0a = [3, 1, 4, 1, 5, 9, 2, 6]
n = len(a)
dp = [1] * n
for i in range(n):
for j in range(i):
if a[j] < a[i]:
dp[i] = max(dp[i], dp[j] + 1)
print(max(dp)) # 4(1,4,5,9 或 1,4,5,6)s1, s2 = "abcde", "ace"
m, n = len(s1), len(s2)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if s1[i-1] == s2[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
print(dp[m][n]) # 3("ace")# 邻接表存图
graph = [[] for _ in range(n + 1)]
# 加一条 u→v 的边
graph[u].append(v)
def dfs(u):
visited[u] = True
for v in graph[u]:
if not visited[v]:
dfs(v)# 数一个 0/1 地图上有几块 1 的连通块
def flood_fill(x, y):
stack = [(x, y)]; a[x][y] = 0
while stack:
i, j = stack.pop()
for dx, dy in [(1,0),(-1,0),(0,1),(0,-1)]:
ni, nj = i + dx, j + dy
if 0 <= ni < n and 0 <= nj < m and a[ni][nj] == 1:
a[ni][nj] = 0; stack.append((ni, nj))
cnt = 0
for i in range(n):
for j in range(m):
if a[i][j] == 1:
cnt += 1
flood_fill(i, j)
print(cnt)flood fill=看一张小岛地图,从一块陆地出发把相连的整片都染色(访问过=淹掉),一块块数出共有几座岛。DFS 或 BFS 都行,关键是"整片一起处理"。
用哈希函数把"键"映射到一个位置(下标),实现 O(1) 的查找/插入/删除。Python 的 dict 和 set 底层就是哈希表。
d = {}
d["apple"] = 3 # 插入/更新
print(d.get("apple")) # 3(O(1) 查找)
s = {1, 2, 3}
print(1 in s) # True(O(1) 判断存在)把哈希表想成按首字母分格子的储物架:找"apple"直接去 A 格拿,不用一格一格翻——这就是哈希函数帮你算好位置。冲突=两个词撞进同一格,用"链子"串起来。
d={}
for ch in s:
d[ch]=d.get(ch,0)+1d.get(ch,0) 取不到返回 0,加 1 计数。套餐 A 或 B 任选一个=加法(2 种);主食+饮料各选一个=乘法(3 主食×2 饮料=6 种)。加"或"、乘"和"——分类相加、分步相乘!
从 n 个不同元素取 k 个排成一列:P(n,k) = n! / (n-k)!,如 3 人排队 P(3,2)=6。
从 n 个元素取 k 个成一组:C(n,k) = n! / (k!(n-k)!),如 3 人选 2 人 C(3,2)=3。
from math import comb, perm
print(comb(5, 2)) # 10 组合
print(perm(5, 2)) # 20 排列n = 6
t = [[0] * (n + 1) for _ in range(n + 1)]
t[0][0] = 1
for i in range(1, n + 1):
for j in range(i + 1):
t[i][j] = (t[i-1][j-1] if j > 0 else 0) + (t[i-1][j] if j < i else 0)
for i in range(n + 1):
print(t[i][:i + 1])杨辉三角第 n 行第 k 个数 = C(n, k)(组合数),每行两边是 1,中间数是肩上两数之和。
杨辉三角就像人墙:最边上站着 1 个人,中间每个人站在下面两个人肩膀上(肩上两数相加),一层层搭起来——每一行的数正好是组合数!
倍增:每次跳 2 的幂次(1、2、4、8…)来快速前进或向上跳,把 O(n) 优化到 O(log n)。典型应用:快速幂、倍增求 LCA、ST 表。
# 快速幂:求 a^b % m
def qpow(a, b, m):
res = 1
while b:
if b & 1: res = res * a % m
a = a * a % m
b >>= 1
return res
print(qpow(2, 10, 1000000007)) # 1024普通一格一格跳 1000 步太慢。倍增=先大步跳 512、256、128…,用二进制把步数拼出来:1000=512+256+128+64+32+8,只跳几次就到位!
# 解一元一次方程 ax + b = 0
a, b = 2, -8
print(-b / a) # 4.0
# 解二元一次方程组(用克莱姆法则)
# a1*x + b1*y = c1 ; a2*x + b2*y = c2
a1, b1, c1 = 1, 1, 5
a2, b2, c2 = 2, -1, 1
det = a1 * b2 - a2 * b1
x = (c1 * b2 - c2 * b1) / det # 2
y = (a1 * c2 - a2 * c1) / det # 3| 图形 | 公式 | |||
|---|---|---|---|---|
| 长 | 方 | 形 | ||
| 长 | × | 宽 |
# Kruskal:按边权从小到大加边,不成环就选(并查集判环)
edges.sort() # [(w, u, v), ...]
fa = list(range(n + 1))
def find(x):
while fa[x] != x:
fa[x] = fa[fa[x]]; x = fa[x]
return x
ans = 0
for w, u, v in edges:
fu, fv = find(u), find(v)
if fu != fv:
fa[fu] = fv; ans += w# Dijkstra:单源最短路(边权非负)
import heapq
dist = [float("inf")] * (n + 1); dist[s] = 0
pq = [(0, s)]
while pq:
d, u = heapq.heappop(pq)
if d > dist[u]: continue
for v, w in graph[u]:
if dist[u] + w < dist[v]:
dist[v] = dist[u] + w
heapq.heappush(pq, (dist[v], v))数 1 到 100 的和:循环加要走 100 步,数学公式 100×101÷2 一步算完——数学优化就是这样用公式省掉大量循环!
edges.sort()
fa=list(range(n+1))
def find(x):
while fa[x]!=x: fa[x]=fa[fa[x]]; x=fa[x]
return x
ans=0
for w,u,v in edges:
if find(u)!=find(v):
fa[find(u)]=find(v); ans+=w
print(ans)按权排序,并查集判环,不成环就加入。import heapq
dist=[inf]*(n+1); dist[s]=0; pq=[(0,s)]
while pq:
d,u=heapq.heappop(pq)
if d>dist[u]: continue
for v,w in g[u]:
if dist[u]+w<dist[v]:
dist[v]=dist[u]+w; heapq.heappush(pq,(dist[v],v))优先队列每次取当前最小距离的点松弛。