2024蓝桥杯训练
Python基础语法记录
此博客记录了为蓝桥杯Python组做的准备
很多地方都会把C++和Python对比起来,以此巩固C++并且熟悉Python
更多都是Python的语法基础
难绷的是,今年蓝桥杯Python组还打水漂了
8个题写了5个题(1个填空题,4个大题,而且不是混分的,是全过程)竟然连三等奖都没,太幽默了
不过问题不大,通过这次准备,接触了很多Python基础语法知识
蓝桥杯而已,不需要这玩意来证明我的能力
初始化数组
一维数组
初始化一个空数组:
1 | List = list() |
空数组不能直接访问下标,但是可以用数组的.append()
方法添加元素
创建一个长1e6
,初始值全为0的数组,有这几种写法:
1 | List = [0] * int(1e6) |
List = [0] * int(1e6)
:这行代码创建了一个长度为1e6的列表,列表中的每个元素都是0。[0]
创建了一个只包含一个元素(即0)的列表,* int(1e6)
将这个列表重复1e6次(虽然
1e6
的值是一个整数,但它的类型是浮点数,所以需要类型转换为int
)
List = [0 for _ in range(int(1e6))]
:这行代码使用了列表推导式来创建一个长度为1e6的列表,列表中的每个元素都是0。for _ in range(int(1e6))
创建了一个循环,循环1e6次,每次循环都生成一个0
import numpy as np
和List = np.zeros(int(1e6))
:这两行代码使用了numpy库来创建一个长度为1e6的numpy数组,数组中的每个元素都是0。np.zeros(int(1e6))
创建了一个长度为1e6的numpy数组,数组中的每个元素都是0
二维数组
在Python中,可以使用列表推导式来创建指定大小的二维数组,初始值全为0。这是一个例子:
1 | # 创建一个5x5的二维数组,初始值全为0 |
列表推导式(List Comprehension)是Python中一种非常方便的创建列表的方法。它可以用一行代码来生成一个新的列表,而不需要使用循环和条件语句。
列表推导式的基本格式如下:
1 >[expression for item in iterable]其中:
expression
是对每个元素进行的操作,可以是任何有效的Python表达式。item
是从iterable
中取出的每个元素。iterable
是任何可迭代的对象,例如列表、元组、集合、字典、字符串等。例如,下面的代码使用列表推导式创建了一个包含10个元素的列表,每个元素都是其索引的平方:
1
2 >squares = [i**2 for i in range(10)]
>print(squares) # 输出:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]你还可以在列表推导式中使用
if
语句来过滤元素。例如,下面的代码创建了一个只包含偶数的列表:
1
2 >evens = [i for i in range(10) if i % 2 == 0]
>print(evens) # 输出:[0, 2, 4, 6, 8]
格式化输入输出
格式化输入
Python其实并不支持格式化输入,比如C中scanf("%1d", &a)
的操作,只能是读取一行的输入然后对输入做相应处理
在Python中,我们通常使用input()
函数来获取用户的输入,然后使用相应的转换函数来将输入转换为所需的类型
input()
函数会将用户的输入作为字符串返回
如果我们需要其他类型的输入,我们可以使用相应的函数来转换输入,例如int()
,float()
等
1 | # 获取一个字符串输入 |
在这个例子中,我们使用input()
函数获取用户的输入,然后使用int()
和float()
函数将输入转换为整数和浮点数
分割函数split()
split()
函数:这个函数用于将一个字符串分割成一个字符串列表;它的工作原理是查找字符串中的空格(或者其他指定的分隔符),然后在每个空格处分割字符串
括号里的参数指定了分隔符,不加默认就是空格作为分隔符
例如,如果你有一个字符串"Hello, World!"
,你可以使用split()
函数将其分割成["Hello,", "World!"]
实际使用中经常把input()
输入函数和split()
分割函数结合在一起使用
例如:
1 | line = input().split() |
在这个例子中,line
变量将包含一个字符串列表,列表中的每个元素都是用户输入的一部分
例如,如果用户输入了"Hello, World!"
,那么line
将会是["Hello,", "World!"]
可以在split()
函数中指定一个分隔符,例如:
1 | s = "Hello,World!" |
parts
变量将会是一个列表,包含["Hello", "World!"]
实际做题中,肯定会碰到输入一行数字的情况,比如输入为7 6 8 11 9
就可以两个函数配合使用input().split()
,得到['7', '6', '8', '11', '9']
可以看到,得到的是字符串列表,再对每一个元素格式化为int
型就处理完了
格式化输出
使用%
操作符进行格式化:
1 | name = "Alice" |
在这个例子中,%s
表示一个字符串,%d
表示一个整数。我们使用%
操作符将name
和age
插入到字符串中
这种写法很类似于C语言的printf()
,但是注意,后面用括号把所有该出现的变量括起来,形成一个“元组”
当然,如果只有一个变量,可以不写成元组的形式
元组(tuple)是一种不可变的序列类型,类似于列表(list)。但与列表不同的是,一旦创建了元组,就不能添加或删除元素,也不能修改元素的值。
使用str.format()
函数进行格式化:
就是对一个字符串调用.format()
函数,函数变量为字符串中出现的变量,字符串里面该出现的变量用{}
做占位符
比如:
1 | name = "Alice" |
在这个例子中,{}
表示一个占位符
我们使用str.format()
函数将name
和age
插入到字符串中
str.format()
函数也可以用于格式化,比如精确到小数点后三位:
1 | result = 3.1415926 |
使用f-string进行格式化(Python 3.6及以上版本):
1 | name = "Alice" |
在这个例子中,f-string
是一种新的字符串格式化方法,它可以直接在字符串中插入变量。
map()
的用法
map()
是Python的内置函数,它的功能是将一个函数应用到一个(或多个)序列的每个元素上,并返回一个迭代器。
在Python中,迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
在大多数情况下,我们会希望直接将迭代器转换为列表,这样就可以一次性获取所有的结果,可以使用
list()
函数来完成这个转换。
map()
函数的基本语法是:map(function, iterable, ...)
function
:这是一个函数,map()
会将这个函数应用到iterable
的每个元素上。iterable
:这是一个(或多个)序列,map()
会遍历这个序列的每个元素。
例如,如果我们有一个列表[1, 2, 3, 4, 5]
,我们想要得到这个列表的每个元素的平方,我们可以使用map()
函数,再将迭代器转换为列表,用list()
:
1 | def square(x): |
配合输入函数input()
,可以解决这样的问题:
[蓝桥杯 2013 省 AB] 错误票据
题目描述
每张票据有唯一的 ID 号,全年所有票据的 ID 号是连续的,但 ID 的开始数码是随机选定的。因为工作人员疏忽,在录入 ID 号的时候发生了一处错误,造成了某个 ID 断号,另外一个 ID 重号。
通过编程,找出断号的 ID 和重号的 ID。
数据保证断号不可能发生在最大和最小号。
输入格式
一个整数 \(N(N<100)\) 表示后面数据行数,接着读入 \(N\) 行数据,每行数据长度不等,是用空格分开的若干个(不大于 \(100\) 个)正整数(不大于 \(10^5\)),每个整数代表一个 ID 号。
输出格式
要求程序首先输入要求程序输出 \(1\) 行,含两个整数 \(m\),\(n\),用空格分隔,其中,\(m\) 表示断号 ID,\(n\) 表示重号 ID。
样例 #1
样例输入 #1
1
2
3 >2
>5 6 8 11 9
>10 12 9样例输出 #1
1 >7 9样例 #2
样例输入 #2
1
2
3
4
5
6
7 >6
>164 178 108 109 180 155 141 159 104 182 179 118 137 184 115 124 125 129 168 196
>172 189 127 107 112 192 103 131 133 169 158
>128 102 110 148 139 157 140 195 197
>185 152 135 106 123 173 122 136 174 191 145 116 151 143 175 120 161 134 162 190
>149 138 142 146 199 126 165 156 153 193 144 166 170 121 171 132 101 194 187 188
>113 130 176 154 177 120 117 150 114 183 186 181 100 163 160 167 147 198 111 119样例输出 #2
1 >105 120
这个如果用c++写,我会这样写:
1 |
|
利用C++里cin
函数的特性,直接作为while
循环的判断:while (cin >> x)
如果在Windows本地跑,需要手动输入ctrl+z模拟文件的EOF,才能正常结束
但是今年蓝桥杯报名的是Python赛道,作为Python初学者,就在此记录解法,更多是语法相关
具体思路和C++的一样:
先创建一个1e6
的数组,全部赋值为0:List = [0] * int(1e6)
再把没用的行数读入:N = int(input())
从输入读数据:
for _ in range(N):
:这是一个循环,会执行N
次。N
是你在之前输入的行数。_
是一个常用的占位符,表示我们不关心循环变量的具体值
line = list(map(int, input().split()))
:这行代码做了几件事情:
input().split()
:input()
函数读取一行输入,split()
函数将这行输入分割成一个字符串列表,分割依据是空格map(int, ...)
:map()
函数对列表中的每个元素应用int()
函数,将字符串转换为整数list(...)
:map()
函数返回的是一个迭代器,list()
函数将迭代器转换为列表
for x in line:
:这是一个循环,会遍历line
列表中的每个元素。每个元素都是一个票据ID
List[x] += 1
:这行代码将List
列表中索引为x
的元素加一。因为每个元素的初始值都是0,所以这行代码实际上是计算每个票据ID的出现次数
再根据List
数组找出断号和重复,完整代码如下
1 | def find_error_tickets(): |
IndexError
先看一道弱质题:
[蓝桥杯 2020 省 AB1] 解码
输入格式
输入一行包含一个字符串。
输出格式
输出一个字符串,表示还原后的串。
样例 #1
样例输入 #1
1 >H3el5o2样例输出 #1
1 >HHHellllloo提示
对于所有评测用例,字符串由大小写英文字母和数字组成,长度不超过 \(100\)。请注意原来的串长度可能超过 \(100\)。
蓝桥杯 2020 第一轮省赛 A 组 F 题(B 组 G 题)。
如果用C++写,很快就拿下了:
1 |
|
但是同样的代码转为Python就给我报错了:
1 | i = 0 |
原因在于 if Str[i+1].isdigit() and i+1 < len(Str):
这一行
首先尝试访问 Str[i+1]
,然后才检查 i+1
是否小于 len(Str)
如果 i
是字符串的最后一个索引,那么
Str[i+1]
就会超出字符串的范围,导致
IndexError
而C++里,if (isdigit(Str[i + 1]) && i + 1 < Str.size())
这样写还是能正常通过,可能是未定义的行为
所以这就是教训:在知道可能会越界的情况下,先判断下标的范围,再尝试访问下标
Python正确代码:
1 | i = 0 |
整数除法//
再来看一道弱质题:
[蓝桥杯 2020 省 B1] 整除序列
题目描述
有一个序列,序列的第一个数是 \(n\),后面的每个数是前一个数整除 \(2\),请输出这个序列中值为正数的项。
输入格式
输入一行包含一个整数 \(n\)。
输出格式
输出一行,包含多个整数,相邻的整数之间用一个空格分隔,表示答案。
样例 #1
样例输入 #1
1 >20样例输出 #1
1 >20 10 5 2 1提示
对于 \(80\%\) 的评测用例,\(1\le n\le10^9\)。
对于所有评测用例,\(1\le n\le10^{18}\)。
蓝桥杯 2020 第一轮省赛 B 组 F 题。
很弱质的题,但是差一个测试点过不了
如果用C++,最后这个测试点应该用long long
数据类型才能过
我用的Python,代码如下:
1 | List = list() |
洛谷题目讨论版给的原因是:
过不了的原因:
n/2
进行double
浮点除法,精度不够。你甚可使用
n>>=1
原因是/
精度不够
于是为了保留整数做除法,可以用//
这个整数除法运算符
也可以用位移运算符>>
完整代码如下:
1 | List = list() |
除了精度不够的问题,Python还有一个问题:浮点数也可以做取余运算%
在C++中,浮点数不能进行%
运算,想要给浮点数取余必须用cmath
头文件中的fmod
函数
但是Python中,数据类型很随意,因此浮点数可以取余,比如:
1 | print(49.97%10) |
这就会导致求一个数字每一位时出现问题,比如弱质题:
[蓝桥杯 2019 省 B] 特别数的和
题目描述
小明对数位中含有 \(2\)、\(0\)、\(1\)、\(9\) 的数字很感兴趣(不包括前导 \(0\)),在 \(1\) 到 \(40\) 中这样的数包括 \(1\)、\(2\)、\(9\)、\(10\) 至 \(32\)、\(39\) 和 \(40\),共 \(28\) 个,他们的和是 \(574\)。
请问,在 \(1\) 到 \(n\) 中,所有这样的数的和是多少?
输入格式
输入一行包含一个整数 \(n\)。
输出格式
输出一行,包含一个整数,表示满足条件的数的和。
样例 #1
样例输入 #1
1 >40样例输出 #1
1 >574提示
对于 \(20\%\) 的评测用例,\(1 \le n \le 10\)。
对于 \(50\%\) 的评测用例,\(1 \le n \le 100\)。
对于 \(80\%\) 的评测用例,\(1 \le n \le 1000\)。
对于所有评测用例,\(1 \le n \le 10000\)。
蓝桥杯 2019 省赛 B 组 F 题。
这里就需要用整数除法//
,就能给浮点数进行C++中int
类型数除等10的操作
代码:
1 | N = int(input()) |
如果想用字符串搜索的方法,在Python中可以使用str()
把一个int
类型的转为字符串,然后调用.find
函数
注意:在C++中,std::string::find
函数如果没找到,函数的返回值会是string::npos
;而在Python中,find
未找到会返回-1,但是在if
判断时,-1会被识别为True
,所以没找到的时候需要把判断条件写对
1 | def check(x): |
字典
先来看一个简单题:
[蓝桥杯 2020 省 AB3] 日期识别
题目描述
小蓝要处理非常多的数据, 其中有一些数据是日期。
在小蓝处理的日期中有两种常用的形式:英文形式和数字形式。
英文形式采用每个月的英文的前三个字母作为月份标识,后面跟两位数字表示日期,月份标识第一个字母大写,后两个字母小写, 日期小于 \(10\) 时要补前导 \(0\)。\(1\) 月到 \(12\) 月英文的前三个字母分别是
Jan
、Feb
、Mar
、Apr
、May
、Jun
、Jul
、Aug
、Sep
、Oct
、Nov
、Dec
。数字形式直接用两个整数表达,中间用一个空格分隔,两个整数都不写前 导
0
。其中月份用 \(1\) 至 \(12\) 分别表示 \(1\) 月到 \(12\) 月。输入一个日期的英文形式, 请输出它的数字形式。
输入格式
输入一个日期的英文形式。
输出格式
输出一行包含两个整数,分别表示日期的月和日。
样例 #1
样例输入 #1
1 >Feb08样例输出 #1
1 >2 8样例 #2
样例输入 #2
1 >Oct18样例输出 #2
1 >10 18提示
蓝桥杯 2020 第三轮省赛 AB 组 F 题。
这个用C++很快能写出来,因为我去年准备天梯赛的时候学了map
的用法,键值对很快就能把这个题写出来,C++代码如下:
1 |
|
用substr
切分字符串,用stoi
把字符串转换为int
,很快就能拿下这个题
Python里有类似map
的方法,是“字典”
在Python中,字典(dictionary)是一种可变容器模型,且可存储任意类型对象。字典的每个键值对(key-value pair)用冒号
:
分割,每个对之间用逗号,
分割,整个字典包括在花括号{}
中。下面是一个简单的字典示例:
1 >my_dict = {"name": "Alice", "age": 20}在这个例子中,"name"和"age"是键(key),"Alice"和20是值(value)。
创建字典
你可以使用花括号
{}
和dict()
函数来创建字典,如下所示:
1
2
3
4
5 ># 使用花括号创建字典
>my_dict = {"name": "Alice", "age": 20}
># 使用dict()函数创建字典
>my_dict = dict(name="Alice", age=20)访问字典中的值
你可以通过键来访问字典中的值,如下所示:
1
2 >my_dict = {"name": "Alice", "age": 20}
>print(my_dict["name"]) # 输出 "Alice"如果你试图访问字典中不存在的键,Python会抛出一个KeyError异常。
修改字典
你可以添加新的键值对,也可以修改已有的值,如下所示:
1
2
3 >my_dict = {"name": "Alice", "age": 20}
>my_dict["age"] = 21 # 修改已有的值
>my_dict["city"] = "New York" # 添加新的键值对删除字典元素
你可以使用
del
语句来删除字典中的元素,如下所示:
1
2 >my_dict = {"name": "Alice", "age": 20}
>del my_dict["age"] # 删除键 "age"你也可以使用
clear()
方法来清空字典中的所有元素,或者使用del
语句来删除整个字典。
所以这段代码转为Python就是:
1 | Mydict = { |
不可变的字符串与join()
函数
还是弱质题:
[蓝桥杯 2013 省 B] 翻硬币
题目背景
小明正在玩一个“翻硬币”的游戏。
题目描述
桌上放着排成一排的若干硬币。我们用
*
表示正面,用o
表示反面(是小写字母,不是零),比如可能情形是**oo***oooo
,如果同时翻转左边的两个硬币,则变为oooo***oooo
。现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢?输入格式
两行等长字符串,分别表示初始状态和要达到的目标状态,每行长度小于 \(1000\)。
数据保证一定存在至少一种方案可以从初始状态和要达到的目标状态。
输出格式
一个整数,表示最小操作步数。
样例 #1
样例输入 #1
1
2 >**********
>o****o****样例输出 #1
1 >5样例 #2
样例输入 #2
1
2 >*o**o***o***
>*o***o**o***样例输出 #2
1 >1提示
source:蓝桥杯 2013 省 B 组 H 题
大概就是从头遍历到尾,如果两个字符串相同就过,如果不相同就翻转字符串2的连续两个,然后count
自增
但是我碰到问题了:
1 | str1=input() |
我在尝试修改str2
的时候,报错:
1 | Traceback (most recent call last): |
bing的解答是:
在Python中,字符串是不可变的数据类型,这意味着你不能直接修改字符串中的某个字符。在你的代码中,你试图直接修改
str2
的值,这是不允许的。如果你想要修改字符串中的某个字符,你可以将字符串转换为列表,然后修改列表中的元素,最后再将列表转换回字符串。以下是修改后的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 >str1 = input()
>str2 = input()
>count = 0
>str2 = list(str2) # 将字符串转换为列表
>for i in range(len(str1) - 1):
if str1[i] != str2[i]:
str2[i] = str1[i]
if str2[i + 1] == '*':
str2[i + 1] = 'o'
else:
str2[i + 1] = '*'
count += 1
>str2 = ''.join(str2) # 将列表转换回字符串
>print(count)
所以如果想修改一个字符串的值,必须用list()
函数转化为列表,然后才能修改
最后,可以用空字符串调用join()
函数,能把列表变回字符串;空字符串在此用作连接符,连接这个数组的元素
关于join()
,此处举例:
1 | str1 = "Hello World" |
输出为:
1 | ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'] #可以看到,list(str1)把str1拆成字符的数组 |
调用
"test".join(str2)
,那么join()
函数会使用"test"
作为连接符,将str2
列表中的所有元素连接成一个字符串。例如,如果
str2
是['a', 'b', 'c']
,那么"test".join(str2)
就会返回'atestbtestc'
。所以,如果你在
join()
函数中使用"test"
作为参数,那么str2
列表中的每个元素之间都会插入"test"
。
如果str2
不是字符数组,而是一个int
数组,又该如何转换:
如果
str2
是一个整数数组,那么''.join(str2)
将会报错,因为join()
方法需要一个字符串列表作为参数,而不是整数列表。但是,你可以通过将整数转换为字符串来解决这个问题。你可以使用 Python 的内置函数
str()
来将整数转换为字符串,然后再使用join()
方法。例如:
1
2
3
4 >str2 = [1, 2, 3]
>str2 = ''.join(str(i) for i in str2)
>#也可以使用下面这种写法,反正都是对str2里的每一个成员调用str()函数,可以用map()然后转为list()
>str2 = list(map(str,str2))在这个例子中,
str(i) for i in str2
是一个生成器表达式,它会遍历str2
中的每个元素i
,并使用str()
函数将i
转换为字符串。然后,''.join()
方法将这些字符串连接起来。