Skip to content

Latest commit

 

History

History
520 lines (400 loc) · 11.4 KB

File metadata and controls

520 lines (400 loc) · 11.4 KB

输入输出

输入

获取输入

python中,使用input函数读取控制台的一行输入

# 输入为: 1 2 3 4 5
a = input()
print(a)
# a = '1 2 3 4 5'

input返回的是一个string

a, b = map(int, input().split(' '))

print(f"{a} and {b}")

快读

import sys

# 读一行
input = lambda: sys.stdin.readline().strip()
# 全读,直到EOF为止
input = lambda: sys.stdin.read().strip()

相当于c++解绑输入输出并关闭流同步

一直不停读

直到捕获到EOF

while True:
    try:
        line = input()
    except EOFError:
        break
    # 处理每一行
    print(line)
import sys
input = lambda: sys.stdin.readline().strip()

while True:
    line = input()
    if line == "":  # 当读到空字符串时认为已经到达 EOF
        break
    # 对每一行进行处理
    print(line)

读到单独的一行换行符也会认为结束,如果不是需要特判

import sys

# 定义 input
input = lambda: sys.stdin.readline()

while True:
    line = input()
    # 判断是否到达 EOF
    if line == "":
        break

    # 如果是一个仅包含换行符的空行,直接打印
    if line == "\n":
        print(line, end="")  # 保留原样输出换行符
    else:
        # 对非空行去除两侧空白,再处理
        line = line.strip()
        # 处理后的行再加上一个换行符输出
        print(line, end="\n")

输出

print

默认结尾会加换行符,可以用end更改

print("有生命\n便有希望",end="")
print("!")

用间隔符可以指定print的每一个元素的间隔

print("谋事在人", "成事在天", "有生命便有希望", sep="&")

快写

假如我们最后要把数组里面的print一遍

import sys

a = [1, 2, 3, 4, 5, 6, 7]

input = lambda: sys.stdin.readline().strip()

output = [str(i) for i in a]

sys.stdout.write("\n".join(output) + "\n")
sys.stdout.write(" ".join(output) + "\n")

# 1
# 2
# 3
# 4
# 5
# 6
# 7

# 1 2 3 4 5 6 7

STL

dict

c++的这种:

map<int, vector<int>> v;
v.insert({1, {}});
v[1].push_back(23);

可以用:

defaultdict(list)

from collections import defaultdict

mp = defaultdict(list)

for i in range(10):
    mp[i].append(i * 2)
    mp[10 - i].append(i * 2)
    
print(mp.items())

setdefault

from collections import defaultdict

mp = {}

for i in range(10):
    mp.setdefault(i, []).append(i * 2)
    mp.setdefault(10 - i, []).append(i * 2)
    
print(mp.items())
dict_items([(0, [0]), (10, [0]), (1, [2, 18]), (9, [2, 18]), (2, [4, 16]), (8, [4, 16]), (3, [6, 14]), (7, [6, 14]), (4, [8, 12]), (6, [8, 12]), (5, [10, 10])])

嵌套列表

像cpp那样的多维vector。

vector<int> v[N];
v[1].push_back(1);
v = [[] for _ in range(10)]
v[a].append(Edge(b, c))

二分

像c++里面的upper_bound(begin, end, value)差不多

  • bisect_left(a, x, lo=0, hi=len(a)) 在从小到大排好序的列表 a 中查找第一个不小于 x(即大于或等于 x)的位置
import bisect

a = [10, 20, 30, 30, 40, 50]
index = bisect.bisect_left(a, 30)
print(index)  # 输出 2,因为 a[2] 是第一个大于等于30的元素
  • bisect_right(a, x, lo=0, hi=len(a)) 或其别名 bisect(a, x, lo=0, hi=len(a)) 在从小到大排好序的列表 a 中查找第一个大于 x 的位置
import bisect

a = [10, 20, 30, 30, 40, 50]
index = bisect.bisect_right(a, 30)
print(index)  # 输出 4,因为 a[4] 是第一个大于30的元素

降序表翻转一下再找即可

队列和栈

python中提供了高层的queue库来实现线程安全的队列栈优先队列等 也有更底层的collections.dequeheapq

前者:

from queue import *

# —— FIFO 队列 ——
q = Queue()
q.put(1)  # 入队 1
q.put(2)  # 入队 2
print("FIFO 队列 peek: front =", q.queue[0], "rear =", q.queue[-1])
print("FIFO 出队:", q.get())  # 出队 -> 1
print("FIFO 出队:", q.get())  # 出队 -> 2

# —— LIFO 栈 ——
stack = LifoQueue()
stack.put("a")  # 入栈 'a'
stack.put("b")  # 入栈 'b'
print("LIFO 栈 peek: top =", stack.queue[-1], "bottom =", stack.queue[0])
print("LIFO 出栈:", stack.get())  # 出栈 -> 'b'
print("LIFO 出栈:", stack.get())  # 出栈 -> 'a'

# —— 优先级队列(最小堆)——(只放入可直接比较的数字)
pq = PriorityQueue()
pq.put(5)
pq.put(1)
pq.put(3)
print("最小堆 peek:", pq.queue[0])
print("最小堆 出队:", pq.get())  # 出队 -> 1
print("最小堆 出队:", pq.get())  # 出队 -> 3
print("最小堆 出队:", pq.get())  # 出队 -> 5

# —— 大根堆(最大堆)——(实现方法:存入的数字取负)
max_pq = PriorityQueue()
max_pq.put(-5)
max_pq.put(-1)
max_pq.put(-3)
# peek操作:取出堆顶的负数,再取相反数
print("大根堆 peek:", -max_pq.queue[0])
# 出队时再取负数以还原原来的值
print("大根堆 出队:", -max_pq.get())
print("大根堆 出队:", -max_pq.get())
print("大根堆 出队:", -max_pq.get())

后者:

from collections import *
import heapq

# —— FIFO 队列 ——
dq = deque()
dq.append(1)  # 入队尾 1
dq.append(2)  # 入队尾 2
print("deque FIFO peek: front =", dq[0], "rear =", dq[-1])
print("deque FIFO 出队:", dq.popleft())  # 出队头 -> 1
print("deque FIFO 出队:", dq.popleft())  # 出队头 -> 2

# —— LIFO 栈 ——
stk = deque()
stk.append("a")  # 入栈 'a'
stk.append("b")  # 入栈 'b'
print("deque LIFO peek: top =", stk[-1], "bottom =", stk[0])
print("deque LIFO 出栈:", stk.pop())  # 出栈 -> 'b'
print("deque LIFO 出栈:", stk.pop())  # 出栈 -> 'a'

# —— 最小堆 ——
# 用列表充当容器
min_heap = []
heapq.heappush(min_heap, 5)
heapq.heappush(min_heap, 1)
heapq.heappush(min_heap, 3)
print("heapq 最小堆 peek:", min_heap[0])
print("heapq 最小堆 出堆:", heapq.heappop(min_heap))  # -> 1
print("heapq 最小堆 出堆:", heapq.heappop(min_heap))  # -> 3
print("heapq 最小堆 出堆:", heapq.heappop(min_heap))  # -> 5

# —— 大根堆 ——(存负数实现)
max_heap = []
heapq.heappush(max_heap, -5)
heapq.heappush(max_heap, -1)
heapq.heappush(max_heap, -3)
print("heapq 大根堆 peek:", -max_heap[0])
print("heapq 大根堆 出堆:", -heapq.heappop(max_heap))  # -> 5
print("heapq 大根堆 出堆:", -heapq.heappop(max_heap))  # -> 3
print("heapq 大根堆 出堆:", -heapq.heappop(max_heap))  # -> 1

后者时间效率更高

sort

sorted函数排序一切可迭代对象,返回一个新的对象

list.sort是原地排序

自定义排序: 使用key关键字

L = ["pear", "apple", "banana", "kiwi", "plum"]
L.sort(key=len) # 按照长度排序
print(L)  # 输出:['kiwi', 'pear', 'plum', 'apple', 'banana']
L = ["pear", "apple", "banana", "kiwi", "plum"]
L.sort(key=lambda s: s[-1])
print(L)  # 输出:['banana', 'kiwi', 'apple', 'pear', 'plum']

lambda s: s[-1] 定义了一个匿名函数,输入是字符串 s,返回其最后一个字符(例如 "pear" 返回 "r"),排序基于这些字符。

也可以自定义命名函数

def count_vowels(s):
    vowels = "aeiouAEIOU"
    return sum(1 for char in s if char in vowels)

L = ["pear", "apple", "banana", "kiwi", "plum"]
L.sort(key=count_vowels)
print(L)  # 输出:['kiwi', 'plum', 'pear', 'apple', 'banana']

key可以等于一个元组,用来复合排序,先按照前面的条件,再按照后面的条件排序

L = ["pear", "apple", "banana", "kiwi", "plum"]
L.sort(key=lambda s: (len(s), s))
print(L)  # 输出:['kiwi', 'pear', 'plum', 'apple', 'banana']

Python 按元组的顺序比较:先比较第一个元素(长度),如果相等再比较第二个元素(字符串本身)。

reverse会颠倒顺序

L = ["pear", "apple", "banana", "kiwi", "plum"]
L.sort(key=lambda s: (len(s), s))
print(L)
L.sort(key=lambda s: (len(s), s), reverse=True)
print(L)

其他

全局变量

函数体内先从内部寻找变量,找不到再去全局找。在函数内使用全局变量需要声明 global

cnt = 0

def dfs(u):
    global cnt
    pass

c++习惯

v = [[] for _ in range(10)]
path = [0] * 10
st = [False] * 10
ans = int(1e18 + 10)

下标从 1 开始再排序怎么做

m = int(input())
# 模拟 1-based,先创建 m+1 个元素的列表,a[0] 不用
a = [None] * (m + 1)

# 从 1 到 m 读入
vals = list(map(int, input().split()))
for i in range(1, m+1):
    a[i] = vals[i-1]

# 对 a[1:] 这段区间排序,排序结果再放回 a[1:]
a[1:] = sorted(a[1:])

# 此时 a[1] … a[m] 就是排好序的
for i in range(1, m+1):
    print(a[i], end=' ')
print()

swap

a = 18
b = 30
a, b = b, a

@dataclass

类似于结构体

from dataclasses import dataclass

@dataclass
class Item:
    id: int
    size: int
    name: str

def main():
    n = int(input())
    items = []
    for _ in range(n):
        _id, sz, nm = input().split()
        items.append(Item(int(_id), int(sz), nm))

    # 按 size 排序
    items.sort(key=lambda x: x.size)

    # 输出
    for it in items:
        print(it.id, it.size, it.name)

if __name__ == "__main__":
    main()

例子:邻接表:

@dataclass
class Edge:
    to: int
    w: int
    
v = [[] for _ in range(10)]

for _ in range(m):
    a, b, c = map(int, input().split(" "))
    v[a].append(Edge(b, c))
    v[b].append(Edge(a, c))

日期类

日期处理,格式化匹配,快速计算两个日期的差值

  • %Y : 四位数的年份(例如,2019)。
  • %y : 两位数的年份(例如,19)。
  • %m : 两位数的月份(01 至 12)。
  • %d : 两位数的日期(01 至 31)。
  • %H : 两位数的小时(24 小时制,00 至 23)。
  • %I : 两位数的小时(12 小时制,01 至 12)。
  • %M : 两位数的分钟(00 至 59)。
  • %S : 两位数的秒钟(00 至 59)。
  • %f : 微秒(000000 至 999999)。
  • %p : 上/下午标记(AM 或 PM)。
  • %z : UTC 偏移,例如 +0000。
  • %Z : 时区名称。
  • %j : 一年中的第几天(001 至 366)。
  • %U : 一年中的星期数(星期日为第一天,00 至 53)。
  • %W : 一年中的星期数(星期一为第一天,00 至 53)
from datetime import datetime

# 示例 1: 仅日期
dt1 = datetime.strptime('2019-11-05', '%Y-%m-%d')
print(dt1)  # 输出: 2019-11-05 00:00:00

# 示例 2: 仅时间
dt2 = datetime.strptime('09:30:50', '%H:%M:%S')
print(dt2)  # 输出: 1900-01-01 09:30:50

# 示例 3: 日期和时间
dt3 = datetime.strptime('2019-11-05 09:30:50', '%Y-%m-%d %H:%M:%S')
print(dt3)  # 输出: 2019-11-05 09:30:50
from datetime import datetime

# 定义两个日期时间对象
dt1 = datetime.strptime('2019-11-05 09:30:50', '%Y-%m-%d %H:%M:%S')
dt2 = datetime.strptime('2020-01-10 15:45:00', '%Y-%m-%d %H:%M:%S')

# 计算两个日期时间的差值
delta = dt2 - dt1

print(delta)               # 输出: 66 days, 6:14:10
print(delta.days)          # 输出: 66 (天)
print(delta.seconds)       # 输出: 22450 (秒) —— 不包括天数转换成秒的部分

# 如果想获取总秒数,可以使用 total_seconds()
print(delta.total_seconds())  # 输出: 总的秒数

memset

可以直接用列表乘法实现

l = [1, 2, 3, 4, 5]
l = [0] * 10
l = [0] * 20
print(l)

增加递归深度

import sys
sys.setrecursionlimit(1000000000)