title: 蓝桥杯python语法速通
tags:
- python
- 蓝桥杯
- 讲座
categories: 讲座
abbrlink: dbd5f3fc
date: 2023-12-09 12:00:00
去个人博客观看体验更佳~
Python 语法
python代码有严格的缩进限制,不同的缩进代表了不同的含义,请不要随意缩进!!!
变量类型
python不需要 预先声明变量,并且没有显式的类型声明,python 代码最后不需要加分号
a = b = c = 1
# 把 a , b , c 都赋值为1
d,e,f = 777 , 3.14159 , "eeee"
# 把d赋值为777, e赋值为小数3.14159 , f赋值为字符串“eee"
数字
数字类型的变量理论上可以存储无限大的数,但是会受限于计算机的运算速度。
str(字符串类型)
不论双引号"ABC"
,还是单引号 ‘ABC’
,代表的都是字符串(即使是'a'
,也是长度为一的字符串,而不是字符)
列表(list)
列表使用中括号表示。
类似于C中的数组,能够存储一些数据,支持按下标找值。列表中可以存放任何类型,并且单个列表可以存放多种类型
a = [0,[1,2,2,5],[[1]] ]
# a[0] = 0
# a[1] = [1,2,2,5]
### a[1][0] = 1 , a[1][3] = 5
# a[2] = [[1]]
# a[2][0][0] = 1
### a[2][0][1] 下标越界!!!
元组(tuple)
元组用小括号()
表示
和列表类似,常用来函数返回多个值
tup = (111,222,"abc") # tup是一个元组
print(type(tup))# <class 'tuple'>
print(tup[1]) # 222
def func():
name = 'ttt'
age = 114
score = 514
return name,age,score
print(func())#('ttt', 114, 514)
元组同样可以使用下标来访问
集合(set)
集合中的元素无序,不重复。
a = {-1,3,-5,3,2,4,4,4}
print(a)#{2, 3, 4, -5, -1}
字典(dict)
字典,顾名思义,就是用来查找值的,每一项是一个键值对,我们通过键可以找到对应的值,每个键值对表示为 key : value .即一个冒号,左边是键,右边是值。
dic = {"mike" : 1000, "Lisa" : 111 , 114 : 514}
其中"mike", “Lisa”,114是键, 1000,111,514 是对应的值。
假设dic是一个字典,使用dic.pop(“mike”) 来清除mike这个键值对。 使用dic[“aaa”] = “ttt” 来加入一个键值对。
如果我们要判断一个键值对是否存在,应该使用
dic = {"mike" : 1000, "Lisa" : 111 , 114 : 514}
dic[222] = 456
print(dic[222])
print(dic.get(222))
dic.pop(114)
if(not dic.get(114)):
print("No!")
输入输出
输入input
输入使用input() 函数,input函数有以下几个特性:
- 会直接读取完一整行
- 读入后的数据以字符串的形式表示
a = input()
print(type(a))
# 输入
## 123 456
# 输出
## <class 'str'>
我们经常需要使用强制类型转换来变成其他形式的值
inum = int(input())
如果一行有多个整数需要输入怎么办???
# 输入
# 1 2 3 4 5 6 7 8 99
## 1.使用input输入一整行
lst = input()# lst = '1 2 3 4 5 6 7 8 99'
## 2.使用字符串的split()函数来将一个字符串分隔开(默认是遇到空格分隔)
lst = input().split() # lst= ['1', '2', '3', '4', '5', '6', '7', '8', '99']
## 3.使用map函数对列表的每一项进行int操作,此时lst是一个map类型
lst = map(int,input().split()) #此时只可以对lst进行遍历,不可以进行下标访问
## 4. 使用list强制转换为列表
lst = list(map(int,input().split()))# list = [1, 2, 3, 4, 5, 6, 7, 8, 99]
输出
格式化输出:
在字符串前加f,然后字符串内加大括号,{}
a = 55
b = "bbb"
print(f"a is {a}, b is {b}")
确定小数位数用:
a = 55.00
print("{:.5f}".format(a))# 保留5位小数
不想让print之后换行
print("abc",end=" ")
print("bcd",end="")
判断
判断和C中的判断基本一样,区别在于 C中的else if 要换成elif
//C code
int a = 77;
if(a < 60){
printf("Bad!\n");
}else if(a < 80){
printf("Good!\n");
}else{
printf("Perfect!");
}
#python code
a = 77
if a < 60 :
print("Bad")#这里必须要缩进
elif (a < 80):
print("Good!")
else:
print("Perfect!")
#Tab键就是缩进
循环
循环一般使用for和while循环:
for循环
for循环用来遍历某个可枚举的类型(集合,列表,元组,字典,range等等)
先来看看range
#只有一个参数时range(n)表示从0 ~ n-1
range(5) # 0 1 2 3 4
# 有两个参数时range(l,r)表示区间[l,r)
# 区间是左闭右开的
range(5,12) # 5 6 7 8 9 10 11
# 有三个参数时range(l,r,step),表示从l到r(取不到r),步长为step
range(3,8,1) # 3, 4 5 6 7
range(3,8,2) # 3 5 7
range(9,3,-2) # 9 7 5
因此我们的for循环应该这么用:
for i in range(8):
print(i)# 0 ~ 7
lst = [5,7,"bcc",123,677.001]
for i in lst:
print(i) #依次输出每一项
while循环
while循环和C中的用法一样,不再赘述
特殊性质
Python中的循环可以加else,表示循环正常结束时进行的操作:(如果使用break中断循环就不会进行else中的操作)
for i in range(5):
print(i)
else :
print(777)
运算
和C相同的运算就不说了,下面说一下不同:
-
整数除法
//
a,b = 5,2 print(a//b) #5 // 2 = 2
-
求次方
**
a,b = 5,3 print(a**b)#5 * 5 * 5 = 125
-
合并数据类型 + *
# str str1,str2 = "AB","CD" print(str1+str2)#ABCD print(str1 * 3) #ABABAB # list lst1 = [1,2,3] lst2 = [3,4,5] print(lst1+lst2)#[1, 2, 3, 3, 4, 5] print(lst1*3)#[1, 2, 3, 1, 2, 3, 1, 2, 3]
一些小技巧(注意点)
快读
-
使用input输入数据比较慢,有时候可能会导致超时,需要换成sys.stdin.readline()
import sys #引入sys库 num = int(sys.stdin.readline())
B2056 求整数的和与均值 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
使用input耗时85ms
n = int(input()) sum = 0 for i in range(n): num = int(input()) sum += num print('{} {:.5f}'.format(sum,sum/n))
使用readline耗时58ms
import sys n = int(sys.stdin.readline()) sum = 0 for i in range(n): num = int(sys.stdin.readline()) sum += num print('{} {:.5f}'.format(sum,sum/n))
注意避免浅拷贝
a1 = [1,2,3,4,5]
b1 = a1
a1[0] = 114514
print(b1) # 114514,2,3,4,5
## 此处由于b1是浅拷贝,导致对a1的修改也会影响b1
a2 = [1,2,3,4,5]
b2 = a2[:]
c2 = a2.copy()
a2[0] = 114514
print(b2) # 1,2,3,4,5
print(c2) # 1,2,3,4,5
## 此处b2和c2都是深拷贝,改变a2不会影响b2和c2
a3 = [[1,2],[3,4]]
b3 = a3[:]
c3 = a3.copy()
a3[0][0] = 114514
print(b3) # [[114514,2],[3,4]]
print(c3) # [[114514,2],[3,4]]
## 这里嵌套列表,导致即使使用了[:] 或者 copy(),但仍然是复制的原始的列表,所以会同步更改
a4 = [[1,2],[3,4]]
b4 = []
for i in range(len(a4)):
tmp = []
for j in range(len(a4[i])):
tmp.append(a4[i][j])
b4.append(tmp)
a4[0][0] = 114514
print(b4) #[[1, 2], [3, 4]]
## 在蓝桥杯中为了保险起见我们可以选择用循环来逐个复制元素
二维数组的定义:
错误样例:
arr = [[0] * 100] * 50
此时当我们使用 a r r [ 5 ] [ 2 ] arr[5][2] arr[5][2], 修改第6行第3列这个元素时,会导致整个第3列都变成这个值(我也搞不懂为什么)
正确示范:
append函数用来向列表的末尾插入一个元素
arr = []
for i in range(50):
arr.append([0] * 100)
快速幂
python的pow函数内置了快速幂
P1226 【模板】快速幂 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
C代码如下:
#include<stdio.h>
#define int long long
int quickpow(int x,int n,int p){
int ans = 1;
while(n){
if(n & 1)
ans = ans * x % p;
x = x * x % p;
n >>= 1;
}
return ans;
}
signed main(){
int a,b,p;
scanf("%lld %lld %lld",&a,&b,&p);
printf("%lld^%lld mod %lld=%lld",a,b,p,quickpow(a,b,p));
}
python代码如下:
a,b,p = list(map(int,input().split()))
print(f"{a}^{b} mod {p}={pow(a,b,p)}")
高精度
python内置了高精度运算
P1601 A+B Problem(高精) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
a,b = int(input()),int(input())
print(a+b)
P1480 A/B Problem - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
a,b = int(input()),int(input())
print(a//b)
自测代码用时
python蓝桥杯中一般会给10s的时间,但我们如何知道我们的代码大概用了多少时间?
import time
tic = time.time()
a = 0
for i in range(int(1e8)):
a += i
tok = time.time()
print(tok-tic) # 8.40402865409851
我们在代码的最上面和最下面分别记录当前的时间,然后输出二者的差。
在我自己的电脑cpu:R6800H
上运行了8.4s, 而一般测评机只会更差,于是我们可以大致估算出python一秒能够支持大概
1
0
7
10^7
107 次算术运算。
datetime
可能不会再出日历题了,但是还是放在这边叭。
# date+time 既有日期也有时间
from datetime import datetime
date_time_1 = datetime(2025,3,29,12,5,13) # 2025年3月29日12时5分13秒
date_time_2 = datetime(2026,6,1,17,5,20) # 2026年6月1日12时5分20秒
delta = date_time_2 - date_time_1 # 代表两个时间之间的差值
print(delta.days) # 天数 429天
print(delta.seconds) # 秒数 18007秒
print(delta.total_seconds()) #37083607.0秒
# date只有日期
from datetime import date
date1 = date(2020, 2, 28) # 定义一个date
date2 = date(2020, 3, 1)
delta = date2 - date1 # 计算两天的差值
print(delta.days) # 2天
# 示例:
# 求从1900年1月1日开始到y年m月d日,有多少个周日?
def cal_sunday(y,m,d):
dat1 = date(1900,1,1)
dat2 = date(y,m,d)
sunday_cnt = 0
while (dat1 < dat2):
if (dat1.weekday() == 6):
sunday_cnt += 1
dat1 += date.resolution # 日期加1天
print(sunday_cnt)
cal_sunday(2025,4,8) # 6536个周日
自定义排序
class Node:
def __init__(self, x, y):
self.x = x
self.y = y
def __lt__(self, other):
if self.x == other.x:
return self.y < other.y
return self.x < other.x
def __repr__(self):
return f"Node(x={self.x}, y={self.y})"
# 示例使用
nodes = [
Node(1, 2),
Node(1, 1),
Node(2, 3),
Node(2, 1),
Node(3, 4)
]
# 排序节点
nodes.sort()
# 打印排序后的节点
# for node in nodes:
# print(node)
# 自定义排序方法的优先队列:
from queue import PriorityQueue
pq = PriorityQueue()
pq.put(Node(1, 5))
pq.put(Node(1, 1))
pq.put(Node(4, 4))
while (not pq.empty()):
print(pq.get())
数据结构
C++转python
此处通过一些“等价”的代码来介绍一些C++和python共同的数据结构。
vector → \to → list
//cpp version
vector<int> vec(114,514);
vec.push_back(1919810);
cout<<vec.back()<<endl;
vec.clear();
cout<< vec.size()<<endl;
# python version
a = [514] * 114
a.append(1919810)
print(a[-1])
a.clear()
print(len(a))
map → \to → dict
注意:
- python中的dict在遍历时并不会保持有序
- python中的dict使用dic[key]访问值,在遇到不存在的key会直接报错。
collections库中包含一个OrderedDict,但这里的ordered指代的”有序“并非像C++那样键的有序。而是保持插入顺序,因此在算法竞赛中通常用不到OrderedDict。
// cpp version
map<int,int> mp;
mp[114] = 514;// 选取某个元素
cout<<mp[2]<<endl; // 访问未定义的键会自动创建然后返回0.
mp.erase(2);// 删除元素
mp.clear();// 清空
for(pair<int,int> pii : mp){// 枚举元素
int x = pii.first;
int y = pii.second;
cout<<x<<" "<<y<<endl;
}
# python version
dic = dict() # 或者 dic={}
dic[114] = 514 # 选取某个元素
# print(dic[2]) # 注意!访问未定义的键会报错 KeyError: 2
print(dic.get(2,0)) # 使用get函数访问,并设置默认值为0 ,注意这样并不会将2加入到dict中,需要手动加入
if(dic.get(2,None) == None): # 判断键是否存在
dic[2] = 0
print("dic[2] is not exist")
dic.pop(2) # 删除元素
dic.clear()# 清空
dic[6] = 1
dic[5] = 2
dic[4] = 3
for x,y in dic.items(): # 枚举元素
print(x,y)
也可以使用collections中的defaultDict,这个数据结构支持为字典定义默认值,从而避免访问不存在的key而报错。
default_dic = defaultdict(lambda:-1) # lambda是一个工厂函数,返回-1
print(default_dic['a']) # 输出-1
dic = dict()
print(dic['a']) # 报错KeyError: 'a'
set → \to → set
注意python中的set是无序的。可以使用sorted来将set变为有序的list。
//cpp version
set<int> st = {1,1,4,5,1,4}; //初始化集合
st.insert(5); // 插入元素
st.erase(5); // 删除元素
cout << st.count(5)<<endl; // 查找某个元素是否存在
cout << *st.begin()<<endl; // 最小的元素
for(int x : st){ // 枚举元素
cout << x << ' ';
}
# python version
st = set([1,1,4,5,1,4]) # 注意st = {} 是字典不是集合
st.add(5) # 插入元素
st.remove(5) # 删除元素
print(5 in st) # 查找某个元素是否存在
for x in st: # 枚举元素,并不会保证有序
print(x,end = ' ')
# python中的set是无序的。
queue → \to → Queue
注意python中的获取队首元素 get方法,会将队首弹出。
而C++中获取首元素que.front()并不会弹出该元素。
虽然queue理论上只能访问队首元素,但是在python的Queue中我们可以直接遍历查看queue的每一个元素的值。
注意Queue的大小写
// cpp version
queue<int> que;
que.push(1);que.push(1);que.push(4); // 推入元素
que.push(5);que.push(1);que.push(4);
cout<< que.front()<<' '<< que.back()<<endl; // 首尾元素
que.pop(); // 队首出队
cout << que.size(); // 队列长度
# python version
from queue import Queue
# 创建一个队列
que = Queue()
que.put(1);que.put(1);que.put(4)# 推入元素
que.put(5);que.put(1);que.put(4)
print(que.queue[0],que.queue[-1]) # 首尾元素
que.get() # 队首出队(返回队首元素并出队)
print(que.qsize()) # 队列长度
for x in que.queue: # 遍历队列
print(x,end=' ')
priority_queue → \to → PriorityQueue
- 注意python中的Priority Queue默认是小根堆(我们可以通过定义一个类,然后重写它的
__lt__
方法,来实现其他排序方式的堆,详见本文之前的“自定义排序”小节。)- 注意PriorityQueue的大小写
// cpp version
priority_queue<int> pq;
pq.push(1); pq.push(1); pq.push(4);
pq.push(5); pq.push(1); pq.push(4); // 插入元素
pq.pop(); // 移出堆顶元素
cout<< pq.top(); // 获取堆顶元素
# python version
from queue import PriorityQueue
pq = PriorityQueue()
pq.put(1);pq.put(1);pq.put(4)
pq.put(5);pq.put(1);pq.put(4) # 插入元素
pq.queue[0] # 选择堆顶元素(不移出)
top = pq.get() # 移出并返回堆顶元素
deque → \to → deque
和queue类似,虽然deque只能从两端进出元素,但我们仍然可以直接枚举整个队列。
// C++ version
deque<int> dq;
dq.push_back(1);dq.push_back(2);dq.push_back(3); // 从右端添加元素
dq.push_front(0); // 从左端添加元素
int right_element = dq.back(); // 从右端移除元素,并打印被移除的元素
dq.pop_back();
cout << right_element << endl; // 输出: 3
int left_element = dq.front(); // 从左端移除元素,并打印被移除的元素
dq.pop_front();
cout << left_element << endl; // 输出: 0
for (const auto& x : dq) { // 打印双端队列
cout << x << " ";
}cout << endl; // 输出: 1 2
int front_element = dq.front();// 获取队首元素(左端)
cout << front_element << endl; // 输出: 1
int back_element = dq.back();// 获取队尾元素(右端)
cout << back_element << endl; // 输出: 2
int queue_size = dq.size();// 获取双端队列的长度
cout << queue_size << endl; // 输出: 2
dq.insert(dq.end(), {3, 4, 5});// 从右端扩展多个元素
for (const auto& x : dq) {
cout << x << " ";
}cout << endl; // 输出: 1 2 3 4 5
dq.insert(dq.begin(), {0, -1});// 从左端扩展多个元素
for (const auto& x : dq) {
cout << x << " ";
}cout << endl; // 输出: -1 0 1 2 3 4 5
for (const auto& x : dq) {// 迭代双端队列中的元素
cout << x << " ";
}cout << endl; // 输出: -1 0 1 2 3 4 5
# python version
from collections import deque
dq = deque() # 创建一个双端队列
dq.append(1) ;dq.append(2);dq.append(3) # 从右端添加元素
dq.appendleft(0) # 从左端添加元素
right_element = dq.pop() # 从右端移除元素,注意该函数返回了被移除的元素。
print(right_element) # 输出: 3
left_element = dq.popleft() # 从左端移除元素
print(left_element) # 输出: 0
print(dq) # 输出: deque([1, 2])
front_element = dq[0] # 获取队首元素(左端)
print(front_element) # 输出: 1
back_element = dq[-1] # 获取队尾元素(右端)
print(back_element) # 输出: 2
queue_size = len(dq) # 获取双端队列的长度
print(queue_size) # 输出: 2
dq.extend([3, 4, 5]) # 从右端扩展多个元素
print(dq) # 输出: deque([1, 2, 3, 4, 5])
dq.extendleft([0, -1]) # 从左端扩展多个元素
print(dq) # 输出: deque([-1, 0, 1, 2, 3, 4, 5])
for x in dq: # 迭代双端队列中的元素
print(x,end = " ")
stack → \to → list
推荐用list来模拟,(类似于C++中的用vector模拟栈)。list的用法详见vector → \to → list 篇