做完之后输出的答案是什么类型需要注意,最好不要循环输出(因为小心最后一个数,不能有空格)
list1 = list(map(int,input().split()));
最后记得根据列表,字典,元组来分类方法
到时候用记事本,tab提示补全
2019,2020所有题,201809,201709第二题
如果出现key可以, key=lambda x:x[1],1可以变,看元组内每个元素里面有几个元素(2,3,3,…)
同时输入多个数字
#2. 同时输入多个数值,字符串间以空格间隔
a,b,c=map(eval,input('同时输入2个数字,以空格间隔:').split())
print(a,b,c);
输入str,可以用for拆分其中的数字
n = input()
sum=0
for i in n:
sum=sum+int(i)
print(sum)
1、直接创建列表(不理大小,不用循环赋值)
nums = list(map(int,input.split(' ')))
print(nums)
结果:
2、去除重复set
list1=[1,2,3,4,4];
a = set(list1);
print(a);
结果:
3、排序,sort,sorted(sorted可以赋值给其他变量,sort不行)
list1=[4,1,3,2];
list1.sort()
print(list1);
结果:
s = [32,453,643,7,0,403,45,0,422,654,4,43,0,53];
s1 = set(s); #set是去重,不会根据顺序去重的,所以在set后排序
dict1 = {}; #定义一个字典,并且赋值
for i in s1:
dict1[i] = s.count(i);
print(dict1);
print("\n看一下dict1.items()是怎么样的",dict1.items(),"\n"); #.items()是元组的意思
maxnum = max(dict1.items(),key=lambda x:x[1]); #这里表示用元组的形式比较,找出所有第二位最大的值
print(maxnum[0]);
d_order = sorted(dict1.items(),key=lambda x:x[0], reverse=True);
print(d_order);
4、查长度,len
list1=[4,1,3,2];
list1.sort()
print(len(list1));
结果:
5、append
list1 = [123, 'xyz', 'zara', 'abc'];
list1.append( 2009 );
print(list1);
结果:
6、count
list1 = [32,543,6543,654,645,0,0,0];
n = list1.count(0);
print(n);
结果:
7、max
list1 = [32,543,6543,654,645,0,0,0];
n = max(list1);
print(n);
8、查找元素位置,index
aList = [123, 'xyz', 'runoob', 'abc']
print "xyz 索引位置: ", aList.index( 'xyz' )
9、输出时用空格间隔,print(1, end=’ ')
list1 = [32,543,6543,654,645,0,0,0];
for i in list1:
print(i,end=' ');
10、查数字
#上面两个例子0是作为元素去查询,如果只有 304 这样的元素里面有0,也是查不到的
list1 = [321,354,764,5,87,3,0,25];
if(0 in list1):
print("里面有0存在");
else:
print("里面没有0存在");
list1 = ["321","354","764","5","87","3","0","25"];
if("0" in list1):
print("里面有0存在");
else:
print("里面没有0存在");
list1 = "423423";
if("0" in list1):
print("里面有0存在");
else:
print("里面没有0存在");
11、返回元素的位置
#列表中最好用index,别用find(find只可以用在字符串上)
s = [32,453,603,7,0,423,45,0,422,654,4,43,0,53];
count = s.count(0);
s1 = str(s);
print(s1);
# print(type(s1));
n=0;
for i in range(count):
print("0在列表中第",s.index(0,n)); # 这里的n表示从第n位开始查找
n = s.index(0,n) +1;
结果:
12、可能会用到的换行,还有结束时用空格隔开
s = [32,453,643,7,0,403,45,0,422,654,4,43,0,53];
#给我输出每个元素出现的次数
for i in s:
print("thank u",end=" ");
print(); #这里用这句话来换行,别用\n否则行距会变得很大
n = len(s);
for i in range(n):
print("thank u", end=" ");
结果:
13、删除列表元素,del
list2 = [343,43,453,23];
del list2[0];
print(list2);
结果:
13、删除列表元素,pop(可以赋值 )
list1 = ['Google', 'Runoob', 'Taobao']
list_pop=list1.pop(1)
print "删除的项为 :", list_pop
print "列表现在为 : ", list1
结果:
14、扭转二维数组:
m,n = list(map(int,input().split())) #定义m行,n列
numbersarray = []
for i in range(0, m): #在列表中再加m行列表,变成矩阵
numbersarray.append(list(map(int, input().split())))
# print(numbersarray)
for x in range(n-1,-1,-1): #2、一共有多少行
for y in range(0, m): #1、每行先输出m个元素
print(numbersarray[y][x],end=' ')
print()
结果:
15、二维数组初始化:
m,n = map(int,input().split());
list1 = [];
list2 = [];
for i in range(n):
list2.append(0);
for i in range(m):
list1.append(list2);
print(list2);
print(list1);
结果:
16、次方还有根号(**2,**0.5)
17、字符串切片
s = '0-670-82162-4';
print(s);
print(s[0:-1]);
print('如果想要输出0-670-82162-X');
print(s[0:-1],end='')
print('X');
结果:
这里需要注意,字符串不可改变,只能用列表方式改变,或者用切片先不输出
18、列表反过来排列
(1)
list2 = [];
list_temp = [];
for i in range(n):
list1 = list(map(int,input().split()));
list2.append(list1);
for i in range(-1,-n-1,-1): #反过来排序
list_temp.append(list2[i][:]);
print(list2);
print(list_temp);
结果:
(2)
li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
print(li[::-1])
结果:
19、二维列表中换位
list2 = [[0, 0, 4, 4], [1, 1, 5, 5], [2, 2, 6, 6]];
list2[0][:],list2[2][:] = list2[2][:],list2[0][:];
print(list2);
结果:
20、从判断跳出循环(201403-2)
for i in range(3):
result = 0;
for j in range(2):
print(j,end=' '); #若只有这里,要输出3次 0 1
if(j ==1):
result=1;
break; #这里的break,只是跳出这个判断而已
if(result==1): #这里的break,已经是跳出了最上面的循环,也就是所有循环,所以输出1次 0 1
break;
结果:
21、replace和eval,字符直接计算
def st190302():
n=int(input())
for i in range(n):
a = input().replace('/','//').replace('x', '*')
num=eval(a)
if num==24:
print('Yes')
else:
print('No')
if __name__ == '__main__':
st190302()
22、字典中get函数
dict = {'Name': 'Runoob', 'Age': 27}
print "Value : %s" % dict.get('Age')
结果:
23、两个列表找相同元素
print(set(a) & set(b))
24、两个列表切片合并成一个列表
#方法一
list1 = [1,2,3,4,5];
list2 = [6,7,8,9,10];
list3 =[];
list3.append(list1[0:3]+list2[2:4]);
print(list3)
#结果:[[1, 2, 3, 8, 9]]
#方法二:
list1 = [1,2,3,4,5];
list2 = [6,7,8,9,10];
list3 =[];
list3.append([list1[0:3],list2[2:4]]);
print(list3)
#结果:[[[1, 2, 3], [8, 9]]]
25、多维列表降维
https://blog.csdn.net/weixin_39564036/article/details/111286230
第二题
二维前缀和必须是正方形矩阵即:n*n;若是后缀和反过来加0
4
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
n=int(input())
a=[]
count=0
for i in range(n):
a.append(list(map(int,input().split())))
for i in range(n):
a[i].insert(0,0) #先给每一行加0
a.insert(0,[0]*(n+1)) #直接加入一行0
print(a)
S=[([0]*(n+1))for i in range(n+1)] #初始化数组
print(S)
for i in range(1,n+1):
for j in range(1,n+1):
Sum=0
Sum+=a[i][j]+S[i-1][j]+S[i][j-1]-S[i-1][j-1]
S[i][j]=Sum
print(S)
for i in range(n+1):
S[i].remove(0)
del S[0];
print(S)
map用于存储稀疏数据是最有效的,也可以用来存储稀疏向量。2个向量不必都存储,能够边读入数据边计算可以节省存储,也有助于提高计算速度。等于字典
优先队列:就像字典排序
贪心法:就像找零一样
第三题:字符串
第四题:算法题
BFS(广度优先搜索)和DFS(深度优先搜索):
https://blog.csdn.net/marxoffice/article/details/97501536
https://developer.51cto.com/art/202004/614590.htm
graph = {
‘A’: [‘B’, ‘C’],
‘B’: [‘A’, ‘C’, ‘D’],
‘C’: [‘A’, ‘B’, ‘D’, ‘E’],
‘D’: [‘B’, ‘C’, ‘E’, ‘F’],
‘E’: [‘C’, ‘D’],
‘F’: [‘D’]
}
def BFS(graph, node):
queue = []#BFS使用栈实现先进先出
queue.append(node)
searched = set()
searched.add(node)
while(len(queue) > 0):
vertex = queue.pop(0)
nodes = graph[vertex]
for node in nodes:
if node not in searched:
queue.append(node)
searched.add(node)
print(vertex)
def DFS(graph, node):
stack = []#DFS使用栈实现先进后出
stack.append(node)
searched = set()
searched.add(node)
while(len(stack) > 0):
vertex = stack.pop()
nodes = graph[vertex]
for node in nodes:
if node not in searched:
stack.append(node)
searched.add(node)
print(vertex)
用Kruskal算法实现。有关最小生成树的问题,使用克鲁斯卡尔算法更具有优势,
https://blog.csdn.net/weixin_44193909/article/details/88774567
graph = {
'vertices':['A', 'B', 'C', 'D'],
'edges':[
(1, 'A', 'B'),
(5, 'A', 'C'),
(3, 'A', 'D'),
(4, 'B', 'C'),
(2, 'B', 'D'),
(1, 'C', 'D'),
]
}
edges=graph['edges']
edges.sort()
vertices=graph['vertices']
trees=[]
direction={}
for vertice in vertices:
direction[vertice]=-1
for edge in edges:
vertice_1=edge[1]
vertice_2=edge[2]
index_1=direction[vertice_1]
index_2=direction[vertice_2]
if index_1<0 and index_2<0:
direction[vertice_1]=len(trees)
direction[vertice_2]=len(trees)
trees.append([edge])
else:
if index_1<0:
direction[vertice_1]=index_2
trees[index_2].append(edge)
if index_2<0:
direction[vertice_2]=index_1
trees[index_1].append(edge)
if not (index_1<0 or index_2<0):
if trees[index_1]!=trees[index_2]:
new_tree=trees[index_1]+[edge]+trees[index_2]
trees[index_1]=new_tree
trees[index_2]=new_tree
print(trees[0])
这是一个强联通图的问题,用Tarjan算法来解决。另外一个算法是kosaraju算法,也用于解决强联通图问题(点点互通,找关键点可以把整个树刚好一分为二)
class HashTable: # 边表
def __init__(self, edges: list, undirected: bool, n: int):
self.hash_map = {}
for i in range(n):
self.hash_map.setdefault(i, set())
for edge in edges:
self.hash_map[edge[0]].add(edge[1])
if (undirected): # 无向图
self.hash_map[edge[1]].add(edge[0])
class Tarjan:
# 强连通分量Strong Connected Component,简称SCC
# 割点/边问题Cut Point/Edge
def __init__(self, n: int, edges: list):
self.n = n
self.edges = [None, None, None]
self.edges[1] = HashTable(edges, False, n)
self.edges[2] = HashTable(edges, True, n)
self.stack = []
self.dfn = [0 for _ in range(self.n)]
self.low = [0 for _ in range(self.n)]
self.index = 0
self.answer_set = [] # 最终的SCC群
self.answer_point = set() # 最终的割点
self.answer_edge = set() # 最终的割边
self.mode = 0 # 为了方便对照,两个问题使用mode变量区分,1为SCC,2为割点边
def reload(self): # 重置
self.stack = []
self.dfn = [0 for _ in range(self.n)]
self.low = [0 for _ in range(self.n)]
self.index = 0
self.answer_set = []
self.answer_point = set()
self.answer_edge = set()
def scc(self): # 强连通分量
self.mode = 1
for i in range(self.n): # 防止漏点
if (self.dfn[i]):
continue
self.targan(i, i)
def cut_point_and_cut_edge(self): # 割点/边问题
self.mode = 2
for i in range(self.n): # 防止漏点(其实这是句废话,初始图不是连通的是啥情况?)
if (self.dfn[i]):
continue
self.targan(i, i)
def targan(self, now: int, father: int):
self.index += 1 # 访问时间戳加1
self.dfn[now] = self.low[now] = self.index # 初始化当前节点的DFN和LOW
if (self.mode == 1):
self.stack.append(now) # 压栈
child_cnt = 0
for i in self.edges[self.mode].hash_map[now]: # 枚举边所能到的点
if (self.dfn[i]): # 已经被处理过
if (i in self.stack and self.mode == 1): # 如果i在栈内,now点能到达的最小时间戳是它自己能到达点的最小时间戳和i的时间戳的min
self.low[now] = min(self.low[now], self.dfn[i])
# 关于为什么是dfn[i],这是因为low[i]可能被搜索树的其它子树更新过了,而
# dfn[i]并不会改变,在强连通分量里,这里改成now[i]没有任何问题,因为强连通分量只关注是不是同一个连通集合,但割点问题不行!
# 割点问题关心的是子树而不是集合,如果改成low[i]会导致子树的low和父树的low一致,导致子树合二为一,从而使得原本子树多于2的子节点无法被找到,从而出现遗漏
if (self.mode == 2):
if (i == father): # 注意不能回头
continue
self.low[now] = min(self.low[now], self.dfn[i])
else: # 没被处理过
child_cnt += 1
self.targan(i, now) # DFS的本质
self.low[now] = min(self.low[now], self.low[i])
if (self.mode == 1):
# 所有的边都访问过后,检查是否为强连通分量根节点(low == dfn)
if (self.low[now] == self.dfn[now]):
scc = set()
while (self.stack[-1] != now): # 开始弹栈
scc.add(self.stack.pop())
scc.add(self.stack.pop()) # 不要忘记了它自己
self.answer_set.append(scc)
if (self.mode == 2):
# 所有的边都访问过后,检查周围是否有low[i] > dfn[now]
if (child_cnt >= 2 and father == now): # 是根且子树多于2个,有割点没割边
self.answer_point.add(now)
for i in self.edges[self.mode].hash_map[now]:
if (self.low[i] >= self.dfn[now] and father != now): # 有割点没割边 注意不能是根节点
self.answer_point.add(now)
if (self.low[i] > self.dfn[now]):
self.answer_edge.add((now, i))
if __name__ == '__main__':
edges = [[0, 2], [2, 1], [1, 0], [2, 3], [3, 4], [4, 5], [3, 6], [6, 2], [2, 7], [7, 6]]
#edges = [[0, 1], [1, 2], [2, 3], [1, 4], [4, 0], [0, 5], [5, 4], [0, 6], [6, 7], [7, 0]]
test = Tarjan(8, edges)
# 强连通分量
test.scc()
print("强连通分量个数:", len(test.answer_set), "\n所有的强连通分量:", test.answer_set, "\n")
test.reload()
# 割点/边问题
test.cut_point_and_cut_edge()
print("割点集合:", test.answer_point, "\n割边集合:", test.answer_edge)
欧拉路径
https://shentuzhigang.blog.csdn.net/article/details/88553573?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control
# 路线图
# 假设:a,b,c,d,e,f,g,h,k,k,l,m 这13个点的代号为0,1,2,3,4,5,6,7,8,9,10,11,12
eulerEdges = [
(0, 2),(0, 1),(0, 3),(0, 4),(1, 2),
(1, 3),(1, 5),(6, 2),(3, 5),(4, 5),
(4, 7),(4 ,10),(5, 6),(5, 8),(5, 11),
(6, 9),(6, 12),(7, 10),(7, 11),(8, 9),
(8, 11),(9, 11),(9, 12),(10, 11),(11, 12)
]# 这个列表里的25个元素均代表一条路径
# 可以通过修改start的值来确定起始位置
start = 3 # 检查员起始位置,笔者认为从效率考虑,应该从d点开始检查
visited = [0 for i in range(len(eulerEdges))] #访问过的路
queue = [] # 保存路径信息
# print(queue)
eulerFlag = False
def isEuler():
allVisited = True
for e in visited:
if e == 0:
allVisited = False
if allVisited:
if queue[0] == queue[len(queue) - 1]:
return 1
else:
return 2
return 0
def printPath(flag):
if flag == 1:
print("是欧拉回路:", end="")
else:
print("是欧拉道路:", end="")
for i in range(len(queue)):
if i < len(queue) - 1:
print(queue[i], "-> ", end="")
else:
print(queue[i])
# 搜索过程只保存一条路的状态的信息,且不重复经过某一路线
def dfs(u):
li = queue.append(u)
flag = isEuler() # 判断当前路径是不是欧拉路,如果是则打印
if flag > 0:
eulerFlag = True
printPath(flag)
for i in range(len(eulerEdges)):
if visited[i] == 1:
continue
edge = eulerEdges[i]
if edge[0] == u:
visited[i] = 1
dfs(edge[1])
#queue.pop() # 将搜索过的点弹出队列
# visited[i] = 0 # 重置访问状态
elif edge[1] == u:
visited[i] = 1
dfs(edge[0])
#queue.pop() # 将搜索过的点弹出队列
# visited[i] = 0 # 重置访问状态
dfs(start)
# if not eulerFlag: # 判断另一种情况
# print("否则:不是欧拉回路或欧拉道路")
这是一个最优化的问题,也是一个单源最短路径问题,所有要用Dijkstra算法
https://blog.csdn.net/weixin_41971381/article/details/104747600?utm_term=dijkstra%E7%AE%97%E6%B3%95python3&utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allsobaiduweb~default-5-104747600&spm=3001.4430
def dijkstra(graph):
l = len(graph)
visit = [i for i in range(6)] # 未遍历点
current = visit[0] # 当前遍历点
path = {} # 最短路径
res = {} # 最短距离
# 0到各个点的初始值
for i in range(l):
res[i] = graph[0][i]
path[i] = '0->{}'.format(i)
while visit:
dtmp = [] # 每次遍历,把当前点到其它点的距离用一个列表按顺序储存起来
for i in range(l):
if current != i:
# 松弛操作
if (res[current] + graph[current][i]) < res[i]:
res[i] = res[current] + graph[current][i]
path[i] = path[current] + '->{}'.format(i)
# 记录当前点到周围点的距离,并排序
if not dtmp:
dtmp.append([i, graph[current][i]])
else:
f = 0
for j in range(len(dtmp)):
if graph[current][i] < dtmp[j][1]:
dtmp.insert(j, [i, graph[current][i]])
f = 1
break
if f == 0:
dtmp.append([i, graph[current][i]])
for i in dtmp:
if i[0] not in visit:
dtmp = dtmp[1:]
else:
visit.remove(i[0])
current = i[0]
break
# print(dtmp)
# print(current,res)
return res, path
if __name__ == '__main__':
graph = [[0, 2, 1, 4, 5, 1],
[1, 0, 4, 2, 3, 4],
[2, 1, 0, 1, 2, 4],
[3, 5, 2, 0, 3, 3],
[2, 4, 3, 4, 0, 1],
[3, 4, 7, 3, 1, 0]]
res, path = dijkstra(graph)
print(res)
print(path)
第二题
试题编号 | 试题名称 | 算法 |
---|---|---|
202104-2 | 邻域均值 | 二维前缀和 |
202012-2 | 期末预测之最佳阈值 | 排序、前缀和以及后缀和 |
202009-2 | 风险人群筛查 | 排序 |
202006-2 | 稀疏向量 | map |
201912-2 | 回收站选址 | map、排序 |
201909-2 | 小明种苹果(续) | 排序 |
201903-2 | 二十四点 | 表达式 |
201812-2 | 小明放学 | 排序、数据类型 |
201809-2 | 买菜 | 排序 |
201803-2 | 碰撞的小球 | 排序、模拟 |
201712-2 | 游戏 | 排序或STL的向量vector或STL的队列queue |
201709-2 | 公共钥匙盒 | 优先队列 |
201703-2 | 学生排队 | 排序或STL的向量vector或STL的list(链表) |
201612-2 | 工资计算 | 数据类型 |
201609-2 | 火车购票 | map |
201604-2 | 俄罗斯方块 | map |
201512-2 | 消除类游戏 | |
201509-2 | 日期计算 | |
201503-2 | 数字排序 | map、排序 |
201412-2 | Z字形扫描 | |
201409-2 | 画图 | |
201403-2 | 窗口 | |
201312-2 | ISBN号码 | 数据类型 |
排序、二维前缀和、map、STL的向量vector、STL的队列queue
第四题
试题编号 | 试题名称 | 算法 |
---|---|---|
202104-4 | 校门外的树 | 打表预处理 |
201612-4 | 压缩编码 | 平行四边形优化 |
201609-4 | 交通规划 | Dijkstra算法、邻接表 |
201604-4 | 游戏 | BFS |
201512-4 | 送货 | 欧拉路径、邻接表、DFS |
201509-4 | 高速公路 | Tarjan算法或kosaraju |
201503-4 | 网络延时 | DFS或BFS |
201412-4 | 最优灌溉 | Kruskal(克鲁斯卡尔)算法或Prim(普里姆) 算法 |
201409-4 | 最优配餐 | BFS |
201403-4 | 无线网络 | BFS |
201312-4 | 有趣的数 | DP(动态规划) |
打表预处理、平行四边形优化、Dijkstra算法、邻接表、BFS、欧拉路径、DFS、Kruskal(克鲁斯卡尔)算法、Prim(普里姆) 算法