算法比赛用到的函数或模块(Python)

输入&输出

python 复制代码
import sys
sys.setrecursionlimit(10**7)  # 设置递归深度,默认为1000,免费午餐,建议使用,以防止递归过深时崩溃
# 允许无限大整数转字符串,防止 n 较大时崩溃
# if hasattr(sys, 'set_int_max_str_digits'):
#     sys.set_int_max_str_digits(0)
input = sys.stdin.readline # 替换 input,免费午餐,建议使用,以提高读取大规模数据的效率
n,d=map(int,input().split()) # 输入接收形式,列表、字典等用推导式
list_q = [list(map(int, input().split())) for _ in range(n)]

# 输出大量数据时,先存入列表再一次性 join,或者:
# sys.stdout.write(str(ans) + '\n')
# 当输出数据规模>10^6时,应该分批输出
print(" ".join(map(str, list_q)))
print(*list_q, sep=" ")

for循环

python 复制代码
students = ['Alice', 'Bob', 'Charlie']
scores = [90, 80, 85]
for student, score in zip(students, scores):
    print(student, score)
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
transposed_matrix = [list(row) for row in zip(*matrix)]
print(transposed_matrix)

f - strings

f"{变量 : [填充字符][对齐方式][宽度][分隔符][.精度][类型]}"

  • 填充字符:指定单个 字符作为填充(需配合对齐符号使用)
  • 对齐方式:<(左)、^(中)、>(右)
  • 宽度:输出的最小宽度,不足部分用填充字符(默认为空格)填充
  • 分隔符:仅可指定,(千分位)或_
  • .精度:指定f类型的小数位数或s类型的最大字符数
  • 类型:d、f、e、E、%、s、b、o、x等
python 复制代码
num = 12345.6789
print(f"严格遵守公式顺序:填充(*) 对齐(^) #前缀(#) 宽度(20) 分隔符(,) 精度(.2) 类型(f)\n{num:*^#20,.2f}")
python 复制代码
# 进制转换
n = 10
print(f"{n:b}")  # 二进制: 1010
print(f"{n:o}")  # 八进制: 12
print(f"{n:x}")  # 十六进制(小写): a
print(f"{n:X}")  # 十六进制(大写): A
# 前缀(#)表示法
print(f"{n:#b}")  # 二进制: 0b1010
print(f"{n:#o}")  # 八进制: 0o12
print(f"{n:#x}")  # 十六进制(小写): 0xa
print(f"{n:#X}")  # 十六进制(大写): 0XA
# int(x,base)函数进行进制转换
# x:要转换的字符串或数字
# base:进制(2-36),默认10
print(int("1010", 2))  # 二进制转十进制:10
print(int("12", 8))  # 八进制转十进制:10
print(int("0a", 16))  # 十六进制转十进制:10
print(int("0A", 16))  # 十六进制转十进制:10
print(f"{int('1010', 2):o}")  # 二进制转八进制: 12
print(f"{int('1010', 2):x}")  # 二进制转十六进制: a

无需导包,直接用的方法

python 复制代码
# abs() 几乎可以完全替代 math.fabs(),且更好
print(abs(-10))  # output:10
# pow() 几乎可以完全替代 math.pow(),且更好
print(pow(2, 3))  # output:8
print(pow(2, 3, 5))  # 快速幂 不要写 2**3%5 output:3
print(divmod(10, 3))  # 10/3=3···1 output:(3,1)
print(*range(10, 0, -1))  # output:10 9 8 7 6 5 4 3 2 1
# 四舍六入五成双(银行家合入法),四舍五入用math.floor(x + 0.5)实现
print(round(2.5))  # output:2
print(round(3.5))  # output:4
print(round(2.3456, 2))  # output:2.35
print(max(1, 2, 3))  # output:3
print(min(1, 2, 3))  # output:1
print(complex(3, 4))  # output:(3+4j)
print(sum([1, 2, 3, 4]))  # output:10
# 执行字符串中的代码
print(eval("5 * 10"))  # output:50
print(len([1, 2, 3]))  # output:3
# zip()将多个可迭代对象中对应的元素打包成一个个元组,
# 然后返回由这些元组组成的一个可迭代对象
# 返回值是迭代器对象
print(list(zip([1, 2, 3], ["a", "b", "c"])))  # output:[(1, 'a'), (2, 'b'), (3, 'c')]
print(*list(zip([1, 2, 3], ["a", "b", "c"])))  # output:(1, 'a') (2, 'b') (3, 'c')
# 将一个可迭代对象组合为一个索引序列,同时列出数据和数据下标。
# 这个函数返回的是一个枚举对象,该对象是一个可以迭代的类型。
# 基本语法为enumerate(iterable, start = 0),start指定索引的起始值,默认为0
fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits, start=1):
    print(index, fruit)
# output:
# 1 apple
# 2 banana
# 3 cherry
list1 = [1, 2, 3]
list2 = ["a", "b", "c"]
for index, (element1, element2) in enumerate(zip(list1, list2)):
    print(index, element1, element2)
# output:
# 0 1 a
# 1 2 b
# 2 3 c
# reversed(iterable)返回一个反向的迭代器对象
print(list(reversed([1, 2, 3])))  # output:[3, 2, 1]
a = 1
b = 0
c = 1
print(all([a > 0, b > 0, c > 0]))  # False
print(any([a > 0, b > 0, c > 0]))  # True

sort()和sorted()

python 复制代码
my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
# sort()是列表专用,对原列表进行排序
my_list.sort(key=None, reverse=False)
print(my_list)  # output:[1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]
names = ["Smith, John", "Doe, Jane", "Johnson, Adam"]
names.sort(key=lambda item: item.split(", ")[1])
print(names)
numbers = [-3, 1, -5, 2]
numbers.sort(key=lambda x: abs(x))
print(numbers)
students = [{"name": "Alice", "grade": 85},
            {"name": "Bob", "grade": 90},
            {"name": "Charlie", "grade": 80}]
students.sort(key=lambda student: student["grade"])
print(students)
'''
output:[{'name': 'Charlie', 'grade': 80}, {'name': 
'Alice', 'grade': 85}, {'name': 'Bob', 'grade': 90}]
'''
my_tuple = (3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5)
# 接受可迭代对象(如列表、元组、字符串等),返回一个新的已排序列表
new_list = sorted(my_tuple, key=None, reverse=False)
print(my_tuple)  # output:(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5)
print(new_list)  # output:[1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]

常用字符串方法

字符串是 不可变对象 (Immutable),所以在字符串的"增、删、改、查"中,"增、删、改"本质上都是在做"字符串拼接"并产生一个新对象

  • 增 可以使用 + 对字符串进行拼接,但是f-strings可以全场景替代 + 且速度略快;批量处理列表,join 比 f-strings更高效

    python 复制代码
    str1 = '123'
    str2 = 'abc'
    str1 = "".join([str1, str2])
    print(str1)  # output: 123abc
  • python 复制代码
    s = "123 abc"
    s = s.replace("3 a", "")
    print(s)  # output:12bc
    s = '123 abc'
    s = s[2:5]
    print(s)  # output:3 a
    # strip():用于去除字符串开头和结尾的指定字符,默认为空白字符(包括空格、制表符、换行符等)
    print(' a b c '.strip())  # output:a b c
    # 只去开头
    print(' a b c '.lstrip())  # output:a b c
    # 只去结尾
    print(' a b c '.rstrip())  # output: a b c
  • python 复制代码
    print('abc abc'.replace('a', 'A'))  # output:Abc Abc
    # 根据转换表(通过maketrans()函数创建)来替换字符串中的字符
    trans_table = str.maketrans("abc", "***")
    print(trans_table)  # {97: 42, 98: 42, 99: 42}
    print('abc123'.translate(trans_table))  # output:***123
  • python 复制代码
    # 查找子字符串第一次出现的位置。
    # 如找到,返回起始索引;如没找到,返回-1
    # find()从左开始查找,rfind()从右开始查找
    print('abc abc'.find('a'))  # output:0
    print('abc abc'.rfind('abc'))  # output:4
    # index(),rindex与find(),rfind()对应,
    # 区别在于没找到,前两个引发ValueError异常,后两个返回-1
    print('abc abc'.index('abc'))  # output:0
    print('abc abc'.rindex('abc'))  # output:4
  • 其它

    python 复制代码
    print(len('abc'))  # output:3
    print('abc abc'.count('abc'))  # output:2
    # ord()返回单个字符的 Unicode 码点,与chr对应
    print(ord('A'))  # output:65
    print(chr(65))  # output:A
    # split()从左开始分割,rsplist()从右开始分割
    print('a,b,c'.split(","))  # output:['a', 'b', 'c']
    print('a,b,c'.rsplit(","))  # output:['a', 'b', 'c']
    print('ABC'.lower())  # output:abc
    print('abc'.upper())  # output:ABC
    print('abc ABC'.swapcase())  # 大小写互换 output:ABC abc
    print('abc abc'.title())  # 单词的首字母转换为大写,其余小写 output:Abc Abc
    print('aBC ABC'.capitalize())  # 字符串首字母转换为大写,其余小写 output:Abc abc
    print('abc abc'.startswith('abc'))  # 判断字符串是否以指定的子字符串开头 output:True
    print('abc abc'.endswith('abc'))  # 判断字符串是否以指定的子字符串结尾 output:True
    print('abc'.isalpha())  # 判断字符串中的所有字符是否都是字母 output:True
    print('123'.isdigit())  # 判断字符串中的所有字符是否都是数字 output:True
    print('ABC'.isupper())  # 判断是否都是大写字母 output:True
    print('abc'.islower())  # 判断是否都是小写字母 output:True
    print('Abc'.istitle())  # 判断首字母是否是大写 output:True
    print('   '.isspace())  # 判断是否都是空白字符。空白字符包括空格、制表符(\t)、换行符(\n)、回车符(\r)等 output:True

常用列表方法

  • python 复制代码
    list = [1, 2, 3]
    list.append(4)  # 在列表的末尾添加一个元素
    print(list)  # output:[1, 2, 3, 4]
    # extend()将一个可迭代对象中的元素逐个添加到列表的末尾。
    list.extend((1, 2, 3))  # 将一个可迭代对象中的元素逐个添加到列表的末尾 '123' [1,2,3]
    print(list)  # output:[1, 2, 3, 4, 1, 2, 3]
    list.insert(1, 4)  # 在索引1的位置插入元素4
    print(list)  # output:[1, 4, 2, 3, 4, 1, 2, 3]
  • python 复制代码
    list = [1, 2, 3, 2]
    list.remove(2)  # 删除第一个匹配的指定元素,如果列表中不存在该元素,则会抛出异常。
    print(list)  # output:[1, 3, 2]
    print(list.pop(1))  # 删除并返回列表中索引2位置的元素 output:3
    print(list)  # output:[1, 2]
  • python 复制代码
    my_list = [1, 2, 3]
    my_list[1] = 6
    my_list[2] = 7
    print(my_list)  # output:[1, 6, 7]
    my_list[1:3] = [2, 3]
    print(my_list)  # output:[1, 2, 3]
  • python 复制代码
    # index()用于返回列表中第一个匹配的指定元素的索引。
    # 如果列表中不存在该元素,则会抛出异常。
    print([1, 2, 3, 2].index(2))  # output:1
  • 其它

    python 复制代码
    list = [3, 1, 4, 1]
    print(list.count(1))  # 统计列表中指定元素出现的次数
    list.sort()  # 对列表中的元素进行排序,默认是升序排序即reverse=False
    print(list)  # output:[1, 1, 3, 4]
    list.sort(reverse=True)  # 对列表中的元素进行降序排序
    print(list)  # output:[4, 3, 1, 1]
    list.reverse()  # 将列表中的元素反转
    print(list)  # output:[1, 1, 3, 4]

常用字典方法

dict:有序、键唯一、值允许重复、可变(Mutable)

  • python 复制代码
    my_dict1 = {'a': 1, 'b': 2}
    my_dict2 = {'b': 3, 'c': 4}
    my_dict1.update(my_dict2)  # 将一个字典中的键-值对更新到另一个字典中
    print(my_dict1)  # output:{'a': 1, 'b': 3, 'c': 4}
  • python 复制代码
    my_dict = {"a": 1, "b": 2, "c": 3}
    value = my_dict.pop("a")  # pop()用于移除字典中指定键的键值对,并返回被移除的值。
    print(my_dict)  # output:{'b': 2, 'c': 3}
    print(value)  # output:1
    try:
        value2 = my_dict.pop("d")  # 如果键不存在,会引发KeyError异常
    except KeyError:
        print("键不存在")  # output:键不存在
    value3 = my_dict.pop("e", 0)  # 可以通过第二个参数指定不存在时的默认返回值
    print(value3)  # output:0
    my_dict = {"a": 1, "b": 2, "c": 3}
    item = my_dict.popitem()  # popitem()移除(以后进先出的顺序)并返回字典中的一个键-值对
    print(my_dict)  # output:{'a': 1, 'b': 2}
    print(item)  # output:('c', 3)
    my_dict.clear()  # clear()用于清空字典中的所有键 - 值对,将字典变为一个空字典
    print(my_dict)  # output:{}
  • python 复制代码
    # setdefault()设置键值对,如果键不存在,在表中增添键值对,返回默认值,默认值可以修改
    dict1 = {"a": 1, "b": 2}
    print(dict1.setdefault("c"))  # output:None
    print(dict1)  # output:{'a': 1, 'b': 2, 'c': None}
    print(dict1.setdefault("d", 4))  # output:4
    print(dict1)  # output:{'a': 1, 'b': 2, 'c': None, 'd': 4}
  • python 复制代码
    dict1 = {'a': 1, 'b': 2}
    # get()获取键对应值,不改变字典,如果键不存在,返回默认值,默认值可以修改
    print(dict1.get('c'))  # output:None
    print(dict1.get('c', 3))  # output:3
    print(dict1)  # output:{'a': 1, 'b': 2}
  • 其它

    python 复制代码
    dict1 = {"a": 1, "b": 2, "c": 3}
    # keys()返回一个可迭代视图对象,表示字典中的所有键
    print(dict1.keys())  # output:dict_keys(['a', 'b', 'c'])
    # values()返回一个可迭代视图对象,表示字典中的所有值
    print(dict1.values())  # output:dict_values([1, 2, 3])
    # items()返回一个可迭代视图对象,其中的每个元素是一个包含键和值的元组
    print(dict1.items())  # output:dict_items([('a', 1), ('b', 2), ('c', 3)])
    for key in dict1.keys():
        print(key)
    # output:
    # a
    # b
    # c
    for value in dict1.values():
        print(value)
    # output:
    # 1
    # 2
    # 3
    for item in dict1.items():
        print(item)
    # output:
    # ('a', 1)
    # ('b', 2)
    # ('c', 3)
    for key, value in dict1.items():
        print(key, value)
    # output:
    # a 1
    # b 2
    # c 3

常用集合方法

set:无序、不允许重复元素、可变(Mutable)

  • python 复制代码
    list1 = {1, 2, 3}
    list1.add(4) # 向集合中添加一个元素
    print(list1) # {1, 2, 3, 4}
    list1.update([5, 6 ,7]) # 将一个可迭代对象中的元素添加到集合中
    print(list1) # {1, 2, 3, 4, 5, 6, 7}
  • python 复制代码
    list1 = {1, 2, 3}
    # 删除指定的元素,如果元素不存在,会抛出KeyError异常。
    print(list1.remove(3))  # output:None
    # 删除指定的元素,如果元素不存在,不会会抛出异常。
    print(list1.discard(3))  # output:None
  • 没有直接修改方法,可以通过删+增进行间接修改

  • python 复制代码
    print(2 in {1, 2, 3})  # output:True
  • 其它

    python 复制代码
    print({1, 2, 3} & {3, 4, 5})  # 求交集,返回一个新的集合 output:{3}
    print({1, 2, 3} | {3, 4, 5})  # 求并集,返回一个新的集合 output:{1, 2, 3, 4, 5}
    print({1, 2, 3} - {3, 4, 5})  # 求差集,返回一个新的集合 output:{1, 2}
    print({1, 2, 3} ^ {3, 4, 5})  # 求对称差集,返回一个新的集合 output:{1, 2, 4, 5}
    print({1, 2, 3} <= ({1, 2, 3}))  # 检查一个集合是否是另一个集合的子集 output:True
    print({1, 2, 3} < ({1, 2, 3}))  # 检查一个集合是否是另一个集合的真子集 output:True

常用元组方法

tuple:有序、允许重复元素、不可变(Immutable)
因为tuple是不可变(Immutable)的,它没有增、删、改的方法

  • python 复制代码
    my_tuple = (1, 2, 3, 2)
    print(my_tuple.index(2))  # index() 返回元组中第一个匹配的指定元素的索引 output:1
  • 其它

    python 复制代码
    my_tuple = (1, 2, 2, 3)
    print(my_tuple.count(2))  # count() 统计元组中指定元素出现的次数 output:2

deque类

  • python 复制代码
    from collections import deque
    
    my_deque = deque([1, 2, 3], maxlen=5)  # 创建一个最大长度为5的双端队列
    my_deque.insert(1, 4)  # 在索引为1的位置插入元素4
    print(my_deque)  # output:deque([1, 4, 2, 3], maxlen=5)
    my_deque.append(5)  # append()在deque的右端(尾部)添加一个元素
    print(my_deque)  # output:deque([1, 4, 2, 3, 5], maxlen=5)
    my_deque.appendleft(6)  # appendleft()在deque的左端(头部)添加一个元素
    print(my_deque)  # output:deque([6, 1, 4, 2, 3], maxlen=5)
    my_deque.extend([7, 8])  # 在deque的右端(尾部)扩展一个可迭代对象
    print(my_deque)  # output:deque([4, 2, 3, 7, 8], maxlen=5)
    my_deque.extendleft([9, 10])  # 在deque的左端(头部)以逆序的方式扩展一个可迭代对象
    print(my_deque)  # output:deque([10, 9, 4, 2, 3], maxlen=5)
  • python 复制代码
    from collections import deque
    
    my_deque = deque([1, 2, 3, 1, 2, 3])  # 创建一个双端队列deque
    last_element = my_deque.pop()  # 删除并返回deque的右端(尾部)的元素
    print(last_element)  # output:3
    print(my_deque)  # output:deque([1, 2, 3, 1, 2])
    first_element = my_deque.popleft()  # 删除并返回deque的左端(头部)的元素
    print(first_element)  # output:1
    print(my_deque)  # output:deque([2, 3, 1, 2])
    my_deque.remove(2)  # 从双端队列deque中移除第一个匹配的元素
    print(my_deque)  # output:deque([3, 1, 2])
  • python 复制代码
    from collections import deque
    
    my_deque = deque([1, 2, 3])  # 使用索引访问deque中的元素
    my_deque[0] = 4
    print(my_deque)  # output:deque([4, 2, 3])
    # pop()+inset()/append()和popleft()+inset()/appendleft()也可以实现修改
  • python 复制代码
    from collections import deque
    
    my_deque = deque([1, 2, 3])  # 使用索引访问deque中的元素
    print(my_deque.index(2))  # output:1
  • 其它

    python 复制代码
    from collections import deque
    
    my_deque = deque([1, 2, 3])
    print(len(my_deque))  # output:3
    my_deque.clear()  # 清空双端队列中的所有元素
    print(len(my_deque))  # output:0
    
    my_deque = deque([1, 2, 3, 4, 5])
    my_deque.rotate(1)  # 将deque中的元素旋转,正数向右旋转,负数向左旋转
    print(my_deque)  # output:deque([5, 1, 2, 3, 4])
    my_deque.rotate(-2)
    print(my_deque)  # output:deque([2, 3, 4, 5, 1])
    
    my_deque1 = deque([1, 2, 3, 1, 2, 3])
    my_deque2 = my_deque1.copy()
    print(my_deque2)  # output:deque([1, 2, 3, 1, 2, 3])
    print(my_deque2.count(1))  # 计算指定元素在双端队列中出现的次数 output:2
    my_deque2.reverse()  # 反转双端队列中的元素顺序
    print(my_deque2)  # output:deque([3, 2, 1, 3, 2, 1])

需要掌握的模块或函数

python 复制代码
import bisect
import copy
import functools
import heapq
import itertools
import math
import sys
from collections import Counter, defaultdict, deque
from datetime import datetime
# 重要程度排序:
# 必用:sys(快速输入输出)、collections.deque(BFS、队列、栈、滑动窗口)
# 高频:collections.defaultdict(图邻接表、计数、分组)、heapq(Top K、Dijkstra、优先队列、堆排序)、collections.Counter(频率统计、字母计数、找众数)、itertools(排列、组合、笛卡尔积)、math(gcd、sqrt、ceil、floor)
# 中频:bisect(二分查找、插入有序列表、等级判定)、functools(递归优化、自定义排序)、copy(深拷贝)
# 低频:datetime(日期计算)、math特殊函数(comb、perm)、itertools高级操作(前缀和、分组)

math

python 复制代码
import math

# 返回大于或等于x的最小整数
print(math.ceil(4.1))  # output:5
# 返回小于或等于x的最大整数
print(math.floor(4.9))  # output:4
# 返回x的平方根。x必须大于等于 0,否则会产生ValueError
print(math.sqrt(9))  # output:3.0
# 返回e的x次幂
print(math.exp(1))  # 2.718281828459045
# 则返回以base为底x的对数,如果没有指定base,则以e为底
print(math.log(10))  # 2.302585092994046
print(math.log(100, 10))  # 2.0
# 分别返回x(弧度制)的正弦、余弦和正切值
print(math.sin(math.pi / 2))  # 1.0
print(math.cos(0))  # 1.0
print(math.tan(math.pi / 4))  # 0.9999999999999999
# 分别返回x的反正弦、反余弦和反正切值(结果是弧度制)
print(math.asin(1))  # 1.5707963267948966
print(math.acos(0))  # 1.5707963267948966
print(math.atan(1))  # 0.7853981633974483
# 将弧度转换为角度
print(math.degrees(math.pi / 2))  # 90.0
# 将角度转换为弧度
print(math.radians(90))  # output:1.5707963267948966
# 返回n!
print(math.factorial(5))  # output:120
# 返回a和b的最大公约数
print(math.gcd(12, 18, 3))  # output:3
# 从5个元素中取出3个元素的组合数
print(math.comb(5, 3))  # output:10
# 计算两个相同维度的点之间的欧几里得距离
print(math.dist((1, 2), (4, 6)))  # output:5.0
print(math.fmod(10, 2))  # output:0.0

heapq

heapq的底层就是普通的Python list,使用type()也返回list类型,这与deque不同

python 复制代码
import heapq

# 创建堆 方法1:从空堆开始
# heap = []
# 创建堆 方法2:从现有列表舰队(推荐,O(n))
heap = [4, 3, 2, 1]
heapq.heapify(heap)  # 将列表原地转换为堆,方法1的空列表不需要heapify
print("初始堆:", heap)  # [1, 3, 2, 4](不一定有序,但满足堆性质)

# 入堆
heapq.heappush(heap, 6)
heapq.heappush(heap, 5)
print("入堆后:", heap)  # [1, 3, 2, 4, 6, 5](不一定有序,但满足堆性质)

# 查看最小值(不删除)
min_val = heap[0]
print("最小值:", min_val)  # 1


# 堆大小
size = len(heap)
print("堆大小:", size)  # 6

# 判空
is_empty = len(heap) == 0
print("是否为空:", is_empty)  # False

# 出堆(弹出最小值)
min_val = heapq.heappop(heap)
print("弹出:", min_val)  # 1
print("出堆后:", heap)  # [2, 3, 5, 4, 6]


# heapreplace = pop + push(更高效)
old_min = heapq.heapreplace(heap, 7)
print("弹出:", old_min)  # 2
print("堆:", heap)  # [3, 4, 5, 7, 6]

# heappushpop = push + pop(更高效)
new_min = heapq.heappushpop(heap, 0)
print("推入0后弹出:", new_min)  # 0
print("堆:", heap)  # [3, 4, 5, 7, 6]

largest_3 = heapq.nlargest(3, heap)
smallest_3 = heapq.nsmallest(3, heap)
print("堆中最大的3个元素:", largest_3)  # [7, 6, 5]
print("堆中最小的3个元素:", smallest_3)  # [3, 4, 5]

# 参数 key 用于指定比较键
students = [
    {"name": "Alice", "score": 85},
    {"name": "Bob", "score": 92},
    {"name": "Charlie", "score": 78},
    {"name": "David", "score": 90},
]
top_two_students = heapq.nlargest(2, students, key=lambda s: s["score"])
print(top_two_students)
# output:[{'name': 'Bob', 'score': 92}, {'name': 'David', 'score': 90}]

itertools

python 复制代码
import itertools

list1 = [1, 2, 3]
list2 = ["a", "b", "c"]
# 返回可迭代对象中元素的所有排列
# 如果r指定长度,则返回指定长度的排列
for i in itertools.permutations(list1):
    print(i)
# output:
# (1, 2, 3)
# (1, 3, 2)
# (2, 1, 3)
# (2, 3, 1)
# (3, 1, 2)
# (3, 2, 1)

for i in itertools.permutations(list1, 2):
    print(i)
# output:
# (1, 2)
# (1, 3)
# (2, 1)
# (2, 3)
# (3, 1)
# (3, 2)

print("==================")

# 1. 普通组合(比如从3个人里选2个去比赛)
print(list(itertools.combinations(list1, 2)))
# output: [(1, 2), (1, 3), (2, 3)]

# 2. 可重复组合(比如买2个水果,可以买2个都是苹果)
print(list(itertools.combinations_with_replacement(list1, 2)))
# output: [(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]

print("==================")

# 不指定repeat,计算多个可迭代对象的笛卡尔积
# 指定repeat,则计算可迭代对象自身的笛卡尔积repeat次
for i in itertools.product(list1, list2):
    print(i)
# output:
# (1, 'a')
# (1, 'b')
# (1, 'c')
# (2, 'a')
# (2, 'b')
# (2, 'c')
# (3, 'a')
# (3, 'b')
# (3, 'c')
# 指定repeat,则计算可迭代对象自身的笛卡尔积repeat次
for i in itertools.product(list1, repeat=2):
    print(i)
# output:
# (1, 1)
# (1, 2)
# (1, 3)
# (2, 1)
# (2, 2)
# (2, 3)
# (3, 1)
# (3, 2)
# (3, 3)
print("==================")
# 将多个可迭代对象连接成一个单一的迭代器
for i in itertools.chain(list1, list2):
    print(i, end=" ")
# output: 1 2 3 a b c

print("\n==================")
accumulated_sum = itertools.accumulate(list1)  # 默认是求和
print(list(accumulated_sum))  # output:[1, 3, 6]
result = itertools.accumulate(list1, lambda x, y: x * y)
print(list(result))  # output:[1, 2, 6]
print("==================")

s = "AAAABBBCCDAA"
for char, group in itertools.groupby(s):
    # group 也是一个迭代器,需要转成 list 才能看长度
    print(f"{char}: {len(list(group))}", end=" ")
# output: A: 4 B: 3 C: 2 D: 1 A: 2
# 注意:它只管连续的!最后的 AA 会被单独分成一组。

# 创建一个从start开始,以step为步长的无限迭代器
for i in itertools.count(1, 2):  # count(start=0, step=1)
    if i > 10:
        break
    print(i, end=" ")
# output:1 3 5 7 9
print()

# 对一个可迭代对象进行无限循环
count = 0
for i in itertools.cycle("ABC"):  # cycle(iterable)
    if count > 5:
        break
    print(i, end=" ")
    count += 1
# output:A B C A B C
print()

# 重复object指定的times次(如果不指定times,则无限重复)
for i in itertools.repeat("Hello", 3):
    print(i, end=" ")
# output:Hello Hello Hello
print("\n==================")

functools

lru_cache

python 复制代码
from functools import lru_cache

@lru_cache(None) # 加上这一行,这题就稳了
def dfs(state):
    if 终止条件: return 0
    # ... 各种递归调用
    return result

sort函数key参数使用 cmp_to_key 时:cmp_to_key 的唯一作用就是接收一个双参数比较函数(即cmp_to_key与双参数比较函数是固定搭配)
cmp_to_key()函数专用于解决最大数问题

题目描述: 给定一组正整数,相邻连接复合成一个最大的整数

python 复制代码
from functools import cmp_to_key


def compare(a, b):
    if a + b > b + a:
        return -1  # a 排在 b 前(降序)
    elif a + b < b + a:
        return 1  # b 排在 a 前
    else:
        return 0


nums = [3, 30, 34, 5, 9]
strs = [str(x) for x in nums]
strs.sort(key=cmp_to_key(compare))
result = "".join(strs).lstrip("0") or "0"
print(result)  # "9534330"

bisect

python 复制代码
import bisect

# 1.必掌握:用 bisect 查找"前驱"和"后继"
arr = [10, 20, 30, 40, 50]
x = 25

# 找到第一个 >= x 的元素
idx = bisect.bisect_left(arr, x)
if idx < len(arr):
    print(f"第一个 >= {x} 的数是: {arr[idx]}")  # 30

# 找到最后一个 <= x 的元素
idx = bisect.bisect_right(arr, x) - 1
if idx >= 0:
    print(f"最后一个 <= {x} 的数是: {arr[idx]}")  # 20


# 2.进阶用法:查表/等级判定
def grade(score):
    breakpoints = [60, 70, 80, 90]
    grades = "FDCBA"
    # bisect 返回插入位置,正好对应 grades 的索引
    i = bisect.bisect_right(breakpoints, score)
    return grades[i]


print([grade(s) for s in [55, 60, 75, 89, 95]])
# output: ['F', 'D', 'C', 'B', 'A']

collections

Counter类

python 复制代码
from collections import Counter

list = [3, 2, 1, 2, 1, 1]
counter_obj = Counter(list)  # Counter是一个容器,用于对可哈希(散列)对象的元素进行计数
print(counter_obj)  # output:Counter({1: 3, 2: 2, 3: 1})
print(counter_obj[1])  # Counter对象可以看作是一个字典子类,可以使用索引访问 output:3

# most_common()返回一个按照元素计数从高到低排序的元组列表
print(counter_obj.most_common())  # output:[(1, 3), (2, 2), (3, 1)]
# 返回出现次数最多的前2个元素及其计数的元组列表
print(counter_obj.most_common(2))  # output:[(1, 3), (2, 2)]

elements_iter = counter_obj.elements()  # elements()方法返回一个迭代器
print(counter_obj)  # output:Counter({1: 3, 2: 2, 3: 1})
for element in elements_iter:  # 该迭代器会根据元素的计数重复返回元素
    print(element, end="")  # output:322111
print()
print("Before clear:", counter_obj)  # output:Before clear: Counter({1: 3, 2: 2, 3: 1})
counter_obj.clear()  # clear()方法用于清空Counter对象中的所有元素计数
print("After clear:", counter_obj)  # output:After clear: Counter()

counter1 = Counter([1, 2, 3])
counter2 = Counter([3, 4, 5])
counter1.update(counter2)  # 传入一个可迭代对象,将其中元素的计数添加到当前Counter对象中
print(counter1)  # output:Counter({3: 2, 1: 1, 2: 1, 4: 1, 5: 1})

defaultdict

python 复制代码
from collections import defaultdict

# 它的主要作用是在访问时字典中不存在的键时,能够返回一个默认值
# 访问前字典是没有默认值的
# 而不是像普通字典那样抛出KeyError异常。

my_dict = defaultdict(int)  # int()的默认值是0
print(my_dict)  # output:defaultdict(<class 'int'>, {})
my_dict["key1"] += 1
print(my_dict["key1"])  # output:1
print(my_dict["key2"])  # output:0

my_list_dict = defaultdict(list)  # list()的默认值是一个空列表
my_list_dict["key1"].append(1)
print(my_list_dict["key1"])  # output:[1]
print(my_list_dict["key2"])  # output:[]


# 自定义默认值函数
def custom_default():
    return ["default value"]


my_custom_dict = defaultdict(custom_default)
print(my_custom_dict["key1"])  # output:['default value']

# 统计一个列表中元素出现的次数,使用defaultdict比使用普通字典更简洁
# 使用defaultdict
my_list = [1, 2, 3, 1, 2]
# 使用defaultdict
count_dict = defaultdict(int)
for i in my_list:
    count_dict[i] += 1
print(count_dict)  # output:defaultdict(<class 'int'>, {1: 2, 2: 2, 3: 1})
print(dict(count_dict))  # output:{1: 2, 2: 2, 3: 1}

# 使用普通字典
count_dict = {}
for i in my_list:
    if i in count_dict:
        count_dict[i] += 1
    else:
        count_dict[i] = 1
print(count_dict)  # output:{1: 2, 2: 2, 3: 1}

deque

deque与list的区别:

  • deque是双端队列,底层实现是分段连续块+指针数组,左右端操作效率属于同一数量级别(右端略微快),因此它有appendleft/append和popleft/pop方法。
  • list的底层实现是一个动态数组,所以右端操作效率远高于左端操作,因此它没有appendleft和popleft方法。
  • 所以当只涉及右端操作时,list和deque的性能差不多;当涉及左端操作时,deque的性能远优于list。

python 复制代码
from collections import deque

# 1.deque实现的栈:
#   deque是双端队列,底层实现是分段连续块+指针数组,左右端操作效率属于同一数量级别(右端略微快),因此它有appendleft/append和popleft/pop方法。
#   所以deque实现的栈的栈顶可以在右端,也可以在左端。
stack = deque(maxlen=None)
stack.append(1)
stack.append(2)
print("入栈后:", stack)
top = stack[-1] if stack else None
print("栈顶元素:", top)
is_empty = len(stack) == 0
print("栈是否为空:", is_empty)
size = len(stack)
print("栈的大小:", size)
stack.pop()
print("出栈后:", stack)

# 2.list实现的栈:
#   list的底层实现是一个动态数组,所以右端操作效率远高于左端操作,因此它没有appendleft和popleft方法。
#   所以list实现的栈的栈顶在右端,入栈和出栈都在右端进行。
stack = []
stack.append(1)
stack.append(2)
print("入栈后:", stack)
top = stack[-1] if stack else None
print("栈顶元素:", top)
is_empty = len(stack) == 0
print("栈是否为空:", is_empty)
size = len(stack)
print("栈的大小:", size)
stack.pop()
print("出栈后:", stack)

队列

python 复制代码
from collections import deque

# 普通队列和双端队列的区别:
# 1.普通队列只能在一端入队,在另一端出队;
# 2.双端队列可以在两端入队和出队。
# 可以根据需要选择append/appendleft和pop/popleft方法来实现不同类型的队列。
queue = deque()
queue.append(1)
queue.append(2)
print(f"入队后的队列: {queue}")  # output: deque([1, 2])
print(f"查看队首元素: {queue[0]}")  # output: 1
print(f"查看队尾元素: {queue[-1]}")  # output: 2
print(f"队列是否为空: {len(queue) == 0}")  # output: False
print(f"队列大小: {len(queue)}")  # output: 2
queue.popleft()
print(f"出队后的队列: {queue}")  # output: deque([2])

并查集(Union-Find)问题

python 复制代码
class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n + 1))  # 父节点数组
        self.rank = [0] * (n + 1)  # 秩(树的高度)
        self.count = n  # 集合数量

    def find(self, x):
        """查找根节点 + 路径压缩"""
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])  # 路径压缩
        return self.parent[x]

    def union(self, x, y):
        """合并两个集合(按秩合并)"""
        root_x = self.find(x)
        root_y = self.find(y)

        if root_x == root_y:
            return False  # 已经在同一集合

        # 按秩合并:将矮树合并到高树下
        if self.rank[root_x] < self.rank[root_y]:
            self.parent[root_x] = root_y
        elif self.rank[root_x] > self.rank[root_y]:
            self.parent[root_y] = root_x
        else:
            self.parent[root_y] = root_x
            self.rank[root_x] += 1

        self.count -= 1  # 集合数量减少
        return True  # 合并成功

    def connected(self, x, y):
        """判断两个元素是否连通"""
        return self.find(x) == self.find(y)


# ========== 示例1:基本使用 ==========
print("=== 示例1:基本使用 ===")
uf = UnionFind(10)

# 合并操作
uf.union(1, 2)
uf.union(2, 3)
uf.union(4, 5)
uf.union(6, 7)
uf.union(7, 8)

# 查询连通性
print(f"1和3连通吗? {uf.connected(1, 3)}")  # True
print(f"1和4连通吗? {uf.connected(1, 4)}")  # False
print(f"6和8连通吗? {uf.connected(6, 8)}")  # True

# 合并不同集合
uf.union(3, 4)
print(f"合并后1和4连通吗? {uf.connected(1, 4)}")  # True

print(f"当前集合数量: {uf.count}")  # output: 4

邻接表(存储结构)

用于实现图和树(无环连通图)

python 复制代码
import sys
sys.setrecursionlimit(10**7)  # 设置递归深度,默认为1000
input = sys.stdin.readline

# n个点, m条边
n, m = map(int, input().split())
adj = [[] for _ in range(n + 1)]  # 下标从1开始比较直观

for _ in range(m):
    u, v, w = map(int, input().split())
    adj[u].append((v, w))  # 存(终点, 权重)
    # adj[v].append((u, w)) # 无向图才加这行

datetime

python 复制代码
from datetime import date, datetime, timedelta

# 1. 创建日期对象
d = date(2026, 3, 30)

# 2. 提取属性 (用于判断条件)
print(d.year, d.month, d.day)
print(d.weekday())  # 0代表周一, 6代表周日(注意:不同于ISO)
print(d.isoweekday())  # 1代表周一, 7代表周日(更符合直觉)

# 3. 日期的加减 (核心技巧:利用 timedelta 遍历)
# 比如:求 100 天后是哪一天
new_d = d + timedelta(days=100)
print(new_d)  # output:2026-07-08


# datetime 几乎用不到
t1 = datetime(2023, 1, 1, 12, 0, 0)
t2 = datetime(2023, 2, 2, 13, 30, 0)

diff = t2 - t1
print(diff.days)  # 相差的天数部分: 1
print(diff.seconds)  # 去掉天数后剩余的秒数: 5400 (1.5小时)
print(diff.total_seconds())  # 总共相差的秒数: 2770200.0
相关推荐
头发够用的程序员14 分钟前
从滑动窗口到矩阵运算:img2col算法基本原理
人工智能·算法·yolo·性能优化·矩阵·边缘计算·jetson
武帝为此38 分钟前
【数据清洗缺失值处理】
python·算法·数学建模
zhangchaoxies1 小时前
如何在 Go 中安全复制接口指针所指向的值
jvm·数据库·python
曲幽1 小时前
FastAPI + Pydantic 模型终极实战手册:从能跑就行到固若金汤,这些技巧你一定用得上
python·fastapi·web·model·field·pydantic·validator·basemodel
Halo_tjn1 小时前
Java 基于字符串相关知识点
java·开发语言·算法
念越2 小时前
算法每日一题 Day08|双指针法解决三数之和
算法·力扣
计算机软件程序设计2 小时前
Python Flask工程目录解读
python·flask·工程目录解读
Ares-Wang2 小时前
Flask》》 Flask-OpenID 认证、 OpenID Connect (OIDC)
后端·python·flask
黎阳之光2 小时前
黎阳之光透明管理:视频孪生重构智慧仓储新范式
人工智能·算法·安全·重构·数字孪生
m0_734949792 小时前
怎么利用Navicat进行调整备份文件压缩等级_详细配置与操作步骤
jvm·数据库·python