(某公司刷kpi用,看一乐)
说明
下文中包括了几道编程题目,请使用Python 3版本来编写代码,并将代码压缩打包以邮件形式发回。
发回的邮箱请参考您收到的邮件中的信息,请在发回的邮件标题中标明您的名字和手机号,以及Python开发字样,例如:Python开发_张三_13800123456。
下面每一道题目中,都有“模板代码”部分,答题时请将模板代码部分的代码复制黏贴到对应的题目代码文件中,按照模板代码部分的TODO注释,填充您的代码。
请将每一道题目的代码,放在单独的Python文件(代码模板有对应的文件名可以直接复制)中,然后把这些文件放到一个文件夹中,将整个文件夹打包,请确保打包文件中删除了Python解释器自动生成的pyc文件,避免代码包过大。
请注意:题目标题中带有“加分题目”字样的题目稍有难度,如果您不会,可以不做,但是做了会得到加分,优先录取。
题目:字符串编辑
给定两个字符串a,b,以及从a到b的一个编辑路径p,求出在编辑路径p上:
1增加了哪些字符,依次以列表形式输出
2减少了哪些字符,依次以列表形式输出
3修改了哪些字符,依次以列表形式输出
说明:
编辑路径p中,'+'表示增加一个字符,'-'表示删除一个字符,'*'表示替换一个字符,'.'表示不变。
举例1:
a = 'a'
b = 'ab'
p = '.+'
输出:
(['b'], [], [])
举例2:
a = 'ab'
b = 'a'
p = '.-'
输出:
([], ['b'], [])
举例3:
输入:
a = 'ab'
b = 'ac'
p = '.*'
输出:
([], [], [('b', 'c')])
举例4:
模板代码,请将下列的模板代码赋值到你的Python代码文件:string_edit.py, 然后在它的基础上实现你的代码:
import time
def show(original: str, changed: str, path: str):
# TODO: 请注释掉下面这一行,并添加你的代码,以让测试都可以通过
add1 = []
add2 = []
add3 = []
offset = 0
for i in range(len(path)):
if path[i] == "+":
add1.append(changed[i - offset])
if path[i] == "-":
add2.append(original[i - offset])
offset += 1
if path[i] == "*":
add3.append((original[i - offset], changed[i - offset]))
expected = (add1, add2, add3) # +add1
return expected
# 代码执行方式, 命令行模式下,进入代码所在根目录,然后执行: python string_edit.py
if __name__ == "__main__":
tests = []
# 1号测试用例
a = "a"
b = "ab"
p = ".+"
expected = (['b'], [], [])
tests.append((a, b, p, expected))
# 2号测试用例
a = 'ab'
b = 'a'
p = '.-'
expected = ([], ['b'], [])
tests.append((a, b, p, expected))
# 3号测试用例
a = 'ab'
b = 'ac'
p = '.*'
expected = ([], [], [('b', 'c')])
tests.append((a, b, p, expected))
# 4号测试用例
a = 'abcdefghijk'
b = '0bcefg1hi2k'
p = '*..-...+..*.'
expected = (['1'], ['d'], [('a', '0'), ('j', '2')])
tests.append((a, b, p, expected))
# TODO: 你是否还可以添加更多的测试用例,来验证你的代码的正确性?
# 5号测试用例
a = 'abcdefghijkabcdefghijk'
b = '0bcefg1hi2k0bcefg1hi2k'
p = '*..-...+..*.*..-...+..*.'
expected = (['1','1'], ['d','d'], [('a', '0'), ('j', '2'),('a', '0'), ('j', '2')])
tests.append((a, b, p, expected))
total_execution_ns = 0
for test_index, one_test in enumerate(tests):
start = time.perf_counter_ns()
result = show(one_test[0], one_test[1], one_test[2])
elapsed = time.perf_counter_ns() - start
total_execution_ns += elapsed
# print(result)
if one_test[3] != result:
print(
f"[{test_index + 1: 2}] 号测试用例执行--失败, 用时: {elapsed}ns, 期望结果是: {one_test[3]}, 实际结果是: {result}")
else:
# print(f"[{test_index + 1: 2}]号测试用例执行--成功, 用时: {elapsed}ns, 期望结果是: {one_test[3]}, 实际结果是: {result}")
print(f"[{test_index + 1: 2}] 号测试用例执行--成功, 用时: {elapsed}ns")
# TODO: 请检查你的代码执行时间,有办法可以让它执行的更快吗?
print(f"\n测试总用时: {total_execution_ns}ns")
题目:公司会议签到表自动统计
这是一道实际的客户需求题目,客户希望将他们的签到信息通过RPA的方式自动的变成结构化数据并给出统计信息,存入客户的OA系统留存。
下图是一张Excel格式的公司会议签到表的截图(具体的Excel内容后文会给出下载链接),您需要编写Python代码按照要求将该Excel中的内容转换成JSON格式、计算统计信息,并基于给定的文本模板格式生成一条发给会议主持人的总结报告。
表格说明:
1表格表头部分是固定的,即会议主题、会议时间、会议主持人、会议地点、会议记录人,序号、部门、姓名、签到、会议状态(缺席、迟到、早退)的位置保持不变。
2表格中间的人员签到登记部分左右分成两个格式相同的区域,这个模式是固定不变的,因此一行最多可以记录两人的信息。
3表格中间的人员签到登记部分的总行数是可以变化的,上图中作为例子只显示了13行,但是实际的会议签到表是可以出现更多的记录行,因此最多可登记的人员也可能会超过26个。
4一个人姓名一列有名字,会议状态未标记为缺席,即为出席。
5表格表尾部分是固定的,即应出席人数,实际出席人数,缺席人数,出席率的位置保持不变。
测试签到表下载:
链接:百度网盘 请输入提取码
提取码:q3ew
请下载文件:公司会议签到表.xlsx (请将下载的文件放在和你的代码文件相同的目录下)
程序要求
输入
上文中您从百度网盘下载的 公司会议签到表.xlsx
输出
JSON信息,输出至文件data.json,JSON信息需要符合以下格式规范,例如上图的正确输出如下所示('#'后的为补充说明,无需输出,# . . . 部分为省略的相似格式内容):
总结报告,输出至文件summary.txt,报告模板格式如下所示,其中红色部分文字是您需要根据Excel中的内容替换掉的文本,黑色部分文字是固定不变的模板文本:
会议星原Studio2.0.0 产品发布部门协调会于2022年5月23日 14:00至16:00进行。我整理了会议签到表,以下是会议参与情况请注意查看。 |
代码要求:
代码版本要求:python3.8
读取excel文件推荐使用的库:openpyxl (相关文档: openpyxl - A Python library to read/write Excel 2010 xlsx/xlsm files — openpyxl 3.1.2 documentation)
代码请写在一个py文件当中
# -*- coding: UTF-8 -*-
import openpyxl
import json
def run(filepath):
myExcel = openpyxl.load_workbook(filepath) # 获取表格文件
mySheet = myExcel['Sheet1']
peoplenum = int(mySheet['C20'].value)
quexi = []
chidao = []
zaotui = []
chidaozaotui =[]
qiandao=[]
qiandao2=[]
zongmingdan = []
zongmingdan_bumen = []
# mySheet.cell()是先行后列,先数字再字母
for i in range(peoplenum):
key=0
zongmingdan.append(str(mySheet.cell(i % 13 + 7, 3 + (7 * (i // 13))).value))
zongmingdan_bumen.append(str(mySheet.cell(i % 13 + 7, 2 + (7 * (i // 13))).value))
qiandao2.append(str(mySheet.cell(i % 13 + 7, 4 + (7 * (i // 13))).value))
if mySheet.cell(i % 13 + 7, 5 + (7 * (i // 13))).value == "√":
quexi.append(str(mySheet.cell(i % 13 + 7, 3 + (7 * (i // 13))).value))
else:
quexi.append("")
if mySheet.cell(i % 13 + 7, 6 + (7 * (i // 13))).value == "√":
chidao.append(str(mySheet.cell(i % 13 + 7, 3 + (7 * (i // 13))).value))
key=1
else:
chidao.append("")
if mySheet.cell(i % 13 + 7, 5 + (7 * (i // 13))).value != "√" and mySheet.cell(i % 13 + 7, 4 + (7 * (i // 13))).value == None:
qiandao.append(str(mySheet.cell(i % 13 + 7, 3 + (7 * (i // 13))).value))
else:
qiandao.append("")
if mySheet.cell(i % 13 + 7, 7 + (7 * (i // 13))).value == "√":
zaotui.append(str(mySheet.cell(i % 13 + 7, 3 + (7 * (i // 13))).value))
key=1
else:
zaotui.append("")
if key==1:
chidaozaotui.append(str(mySheet.cell(i % 13 + 7, 3 + (7 * (i // 13))).value))
else:
chidaozaotui.append("")
#chidaozaotui=list(set(chidao.extend(zaotui)))
chaosong=""
absent=""
absent_count=0
notsigned=""
for i in range(len(chidaozaotui)):
if chidaozaotui[i] != "":
chaosong+= chidaozaotui[i]+"("+zongmingdan_bumen[i]+")、\n"
chaosong = chaosong[:-2]
for i in range(len(quexi)):
if quexi[i] != "":
absent+=quexi[i]+"("+zongmingdan_bumen[i]+")、"
absent_count+=1
absent= absent[:-1]
for i in range(len(qiandao)):
if qiandao[i]=="":
continue
notsigned+=qiandao[i]+"、"
notsigned =notsigned[:-1]
n = {}
a = json.loads(json.dumps(n))
a['主题'] = mySheet['C2'].value
time=mySheet['C3'].value # 2022年5月23日 14:00~16:00
year=time.split('年')
month=year[1].split('月')
day=month[1].split('日')
time1=day[1].split('~')
a['日期']="%s-%s-%s"%(year,month,day)
a['开始时间']=time1[0].strip()
a['结束时间']=time1[1].strip()
a['地点'] = mySheet['J3'].value
a['主持人']=mySheet['C4'].value
a['记录人']=mySheet['J4'].value
a['应出席人数']= int(mySheet['c20'].value)
a['实际出席人数']= int(int(mySheet['c20'].value) - absent_count) # 【表格中该区域可能会没有填,需要自己计算,未标记为缺席即为出席】
a['缺席人数']= int(absent_count) # 【表格中该区域可能会没有填,需要自己计算】
a['出席率']= "%.1f%%" % ( 100 - absent_count / (int(mySheet['c20'].value)) * 100) # 【表格中该区域可能会没有填,需要自己计算,格式需要为百分比形式,且仅保留小数点后一位】
a["参会人详细信息"]=[]
for i in range(int(mySheet['c20'].value)):
chuxizhuangtai="出席"
if quexi[i]!="":
chuxizhuangtai = "缺席"
shifouchidao=False
if chidao[i]!="":
shifouchidao = True
shifouzaotui=False
if zaotui[i]!="":
shifouzaotui =True
a["参会人详细信息"]+=[ {
"姓名": "%s"%(zongmingdan[i]),
"部门": "%s"%(zongmingdan_bumen[i]),
"签到": "%s"%(qiandao[i]), # 【若表格中此处为空,则用""空字符串表示】
"出席状态": chuxizhuangtai, # 【状态仅有两种,出席和缺席】
"是否迟到": shifouchidao, # 【状态仅有两种,true和false,bool值类型】
"是否早退": shifouzaotui # 【状态仅有两种,true和false,bool值类型】
}]
a["各组出勤情况"] = {}
li = list(set(zongmingdan_bumen))
L=[[0 for i in range(len(li))] for j in range(4)]
for i in range(int(mySheet['c20'].value)):
for j in range(len(li)):
if zongmingdan_bumen[i]==li[j]:
L[0][j]+=1
if quexi[i]=="":
L[1][j]+=1
if chidao[i]!="":
L[2][j]+=1
if zaotui[i]!="":
L[3][j]+=1
continue
for i in range(len(li)):
a["各组出勤情况"]["%s"%(li[i])]={
"应出勤人数": L[0][i],
"实际出勤人数": L[1][i],
"出勤率": "%.0f%%" % ( L[1][i]/ L[0][i] * 100),
"迟到比例": "%.0f%%" % ( L[2][i]/ L[0][i] * 100), # 【迟到人数/实际出勤人数】
"早退比例": L[3][i]/ L[0][i]
}
b = json.dumps(a,ensure_ascii=False, indent = 2)
f2 = open('new_json.json', 'w',encoding='utf-8')
f2.write(b)
f2.close()
with open('summary.txt', 'a', encoding='utf-8') as f: # 'a'表示append,即在原来文件内容后继续写数据(不清楚原有数据)
f.seek(0)
f.truncate()
content_s = "会议" + str(mySheet['C2'].value) + "于" + str(
mySheet['C3'].value) + "进行。我整理了会议签到表,以下是会议参与情况请注意查看。\n"
f.writelines(content_s)
f.writelines("会议应出席" + str(mySheet['C20'].value) + "人,"
"实际出席" + str(mySheet['E20'].value) + "人,"
"其中"+absent +"(" + str(mySheet['J20'].value) +
"位)缺席会议。\n\n")
f.writelines("由于部分同事来迟或提前离开,请会后将会议全程录屏抄送给他们:\n\n"+chaosong)
f.writelines("\n\n签到表上部分同事未来得及签名,可否通知他们来我这里补签,非常感谢。\n未签到同事:"+notsigned)
f.close()
# 请在此处实现代码,结果输出至data.json和summary.txt中
# 代码执行方式, 命令行模式下,进入代码所在根目录,然后执行: python meeting_summary.py
# 请确保下载的测试文件放在了和代码相同的目录下
if __name__ == '__main__':
run("公司会议签到表.xlsx")
模板代码,请将下列的模板代码赋值到你的Python代码文件:meeting_summary.py, 然后在它的基础上实现你的代码:
题目:计算数学表达式(加分题目)
解析并计算数学表达式,操作数为整数或浮点数,操作符包括“加减乘除“。支持“括号”操作符作为选做部分。
●输入为合法的表达式字符串,包含数字/小数点/加减乘除符号/空格;在选做部分中,输入还可能包含左右圆括号,操作符右侧出现带负号的操作数时,负号和其操作数必然放在一对括号里,例如1 - (-1),2 * (-3),4 * (-(5 + 6))。
●输出计算出的表达式的值。
请注意:不能直接使用python内置方法'eval'或'exec'。
测试用例:
模板代码,请将下列的模板代码赋值到你的Python代码文件:eval_expression.py, 然后在它的基础上实现你的代码:
import time
class Solution:
def calculate(self, s: str):
# 第一处替换是去除空白字符
# 第二处替换是要在括号以负号开头添加前导0,否则数字栈数字对不上。第三处替换是将"--1"这种格式变成“+1”这种格式
# 第二第三处替换均为特殊情况
s = s.replace(" ", "").replace("(-", "(0-").replace("--", "+") + "+"
length = len(s)
# 定义两个栈分别存放运算符和数字
op_stack, num_stack = [], []
print(s)
i = 0
# 定义运算符优先级
op_priority = {'+': 0, '-': 0, '*': 1, '/': 1, '%': 1}
while i < length:
c = s[i]
# 判断c是否是数字
if c.isdigit():
num = 0
while s[i].isdigit():
num = num * 10 + int(s[i])
i += 1
# 跳出while循环后i所指的字符已经是运算符,因为大循环每结束一次都要加1,所以这里要退一步,之后再在大循环结束一次后加1
i -= 1
num_stack.append(num)
elif c == '(':
op_stack.append(c)
elif c == ')':
# 不断将括号内没有计算完的表达式计算完,直到遇到左括号为止。
# 注意:括号内表达式的运算符优先级已经是由低到高排序了(一低一高),可以直接调用calc方法计算而无需考虑运算符优先级问题
# 因为遍历到“后”运算符时如果“前”运算符优先级大于“后”运算符会取出栈内元素进行计算,
# 计算后“前”运算符会消失,然后“后”运算符会压入栈中。也就是说只有符合优先级由低到高排序才能继续存在括号内,否则会被提前消除
while op_stack[-1] != '(':
self.calc(num_stack, op_stack)
# 将左括号弹出
op_stack.pop()
# 运算符分支
else:
# 特殊情况:当表达式出现 6/-2+5这种类型时,我们要给-2加上对括号和前导0变成 6/(0-2)+5才能继续计算
if s[i - 1] in "*/" and c == "-":
num_stack.append(0)
op_stack.append("(")
# 遍历往后字符串,直至遇到运算符或右括号为止,再其前面插入一个右括号
# 注意: 数字后面不能是左括号
f = i + 1
while s[f] not in ")+-*/":
f += 1
s = s[:f] + ")" + s[f:]
length += 1
# “(”不是运算符没有优先级,在栈顶时不能参与优先级比较。
while op_stack and op_stack[-1] != '(':
prev_op = op_stack[-1]
# 唯有当栈顶运算符的优先级小于此时运算符的优先级才不会被计算,即“前”运算符优先级小于“后”运算符优先级不会被计算(消除)。如 前面为“+”后面为“/”
if op_priority[prev_op] >= op_priority[c]:
# 将两个栈传过去后,相同的地址可以直接将两栈修改,而无需返回处理后的新栈再接收栈
self.calc(num_stack, op_stack)
else:
break
op_stack.append(c)
i += 1
print(num_stack, op_stack)
print(s)
return num_stack[0]
def calc(self, num_stack: list, op_stack: list):
# 每调用一次该函数,数字栈里面至少有一个元素,只有连续出现两次运算符,数字栈才有可能为空, 这种计算x,y都需要补0。而这样的表达式一般只有"++1"这类情况
# 一般情况下都不为0,或x(比y先出现的数字)才有可能是0,如-5的计算应看作0-5
op, y, x = op_stack.pop(), num_stack.pop() if num_stack else 0, num_stack.pop() if num_stack else 0
ans = 0
if op == '+':
ans = x + y
elif op == '-':
ans = x - y
elif op == '*':
ans = x * y
elif op == '/':
ans = x / y
elif op == '%':
ans = x % y
# 使用round函数保留5位小数
num_stack.append(round(ans, 5))
def my_eval(expression: str) -> float:
# TODO: 请注释掉下面这一行,并添加你的代码,以让测试都可以通过
return (Solution().calculate(expression))
return answer
# 注:不能直接使用python内置方法'eval'或'exec'
# 代码执行方式, 命令行模式下,进入代码所在根目录,然后执行: python eval_expression.py
if __name__ == "__main__":
tests = []
# 1号测试用例
src = "1 + 2"
expected = 3
tests.append((src, expected))
# 2号测试用例
src = "1 + 2 * 3"
expected = 7
tests.append((src, expected))
# 3号测试用例
src = "1 * 2 - 3 / 4"
expected = 1.25
tests.append((src, expected))
# 4号测试用例(选做)
src = "76 * (54 - 32) / 11"
expected = 152
tests.append((src, expected))
# TODO: 你是否还可以添加更多的测试用例,来验证你的代码的正确性?
total_execution_ns = 0
for test_index, one_test in enumerate(tests):
start = time.perf_counter_ns()
result = my_eval(one_test[0])
elapsed = time.perf_counter_ns() - start
total_execution_ns += elapsed
# print(result)
if one_test[1] != result:
print(f"[{test_index + 1: 2}] 号测试用例执行--失败, 用时: {elapsed}ns, 期望结果是: {one_test[1]}, 实际结果是: {result}")
else:
# print(f"[{test_index + 1: 2}]号测试用例执行--成功, 用时: {elapsed}ns, 期望结果是: {one_test[1]}, 实际结果是: {result}")
print(f"[{test_index + 1: 2}] 号测试用例执行--成功, 用时: {elapsed}ns")
# TODO: 请检查你的代码执行时间,有办法可以让它执行的更快吗?
print(f"\n测试总用时: {total_execution_ns}ns")
题目:找到最大激活区域(加分题目)
给定一个M×N 的二维矩阵(二维数组)mat,M≥1 且N≥1 ,matij元素代表i行j列的值,类型为 bool。matij等于 True,表示该元素已被激活,反之则未被激活。
如果两个已激活的元素是相邻的(指上下、左右紧挨着算相邻,对角紧挨着不算相邻),则这两个元素属于同一个激活区域,即激活区域是由一片联通的已经激活的相邻的元素连接构成。定义激活区域的大小为其中激活元素的个数。
以下图为例,图示 8x8 矩阵中有两个激活区域(绿色),左上方的激活区域大小是 5,右下方的激活区域大小是 3。
请实现一个算法,找到并返回最大的激活区域的大小。以上图为例,算法需要返回 5。
模板代码,请将下列的模板代码复制到你的 Python 代码文件:find_the_largest_area.py, 然后在它的基础上实现你的代码:
from typing import Sequence
import time
area=0
area_big=0
L = [[-2 for i in range(10)] for j in range(10)]
def ext(i,j):
L[i][j]=2
if L[i+1][j]==1:
ext(i+1,j)
if L[i-1][j]==1:
ext(i-1,j)
if L[i][j+1]==1:
ext(i,j+1)
if L[i][j-1]==1:
ext(i,j-1)
def cal(i,j):
global area,area_big
global L
L[i][j]=2
ext(i,j)
print(L)
area=0
for i in range(len(mat)):
for j in range(len(mat[0])):
if L[i][j] == 2:
area+=1
for i in range(len(mat)):
for j in range(len(mat[0])):
if L[i][j] == 2:
L[i][j] = 0
area_big = max([area_big,area])
#print(L)
print(L)
ii=0
jj=0
for i in range(len(mat)):
for j in range(len(mat[0])):
if L[i][j] == 1:
ii=i
jj=j
cal(ii, jj)
return area_big
def find_the_largest_area(mat: Sequence[Sequence[bool]]) -> int:
# TODO: 请注释掉下面这一行,并添加你的代码,以让测试都可以通过
ii=0
jj=0
for i in range(len(mat)):
for j in range(len(mat[0])):
if mat[i][j]:
L[i+1][j+1]=1
ii=i+1
jj=j+1
else:
L[i+1][j+1]=0
#print(ii,jj)
return cal(ii,jj)
#raise NotImplementedError()
# 代码执行方式, 命令行模式下,进入代码所在根目录,然后执行: python find_the_largest_area.py
if __name__ == "__main__":
tests = []
# 1 号测试用例
mat = [
[False, False, False, False, False],
[False, True, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
]
excepted = 1
tests.append((mat, excepted))
# 2 号测试用例
mat = [
[False, False, False, False, False],
[False, True, True, False, False],
[False, True, False, False, False],
[False, False, True, True, False],
[False, False, False, False, False],
]
excepted = 3
tests.append((mat, excepted))
# 3 号测试用例
mat = [
[False, False, False, False, False, False, False, False],
[False, True, True, False, False, False, False, False],
[False, True, False, False, False, False, False, False],
[False, True, True, False, False, False, False, False],
[False, False, False, False, True, True, False, False],
[False, False, False, False, True, False, False, False],
[False, False, False, False, False, False, False, False],
[False, False, False, False, False, False, False, False],
]
excepted = 5
tests.append((mat, excepted))
# TODO: 你是否还可以添加更多的测试用例,来验证你的代码的正确性?
total_execution_ns = 0
for test_index, (mat, excepted) in enumerate(tests, start=1):
start = time.perf_counter_ns()
result = find_the_largest_area(mat)
elapsed = time.perf_counter_ns() - start
total_execution_ns += elapsed
if result != excepted:
print(f"[{test_index: 2}] 号测试用例执行--失败, 用时: {elapsed}ns, "
f"期望结果是: {excepted}, 实际结果是: {result}")
else:
print(f"[{test_index: 2}] 号测试用例执行--成功, 用时: {elapsed}ns")
# TODO: 请检查你的代码执行时间,有办法可以让它执行的更快吗?
print(f"\n测试总用时: {total_execution_ns}ns")