第 15 题
答案与解析
第(2)①小题
6
程序分析
for i in range(1, n):
key = data[i]
...外层循环从 i=1 开始,data[0] 先单独构成已有序部分。每一轮取出 data[i] 并保存为 key,再通过下面的内层过程把它插入前面的已有序部分;一轮结束后,已有序范围增加一个元素。
j = i - 1
while j >= 0:
if data[j][0]>key[0] or (data[j][0]==key[0] and data[j][1]<key[1]):
data[j + 1] = data[j]
j -= 1
else:
break
data[j + 1] = keyj=i-1 使 j 从已有序部分的末端开始向左比较。当已有元素的到达时间晚于 key,或到达时间相同但规格字母小于 key 时,该元素应排在 key 后面,于是加框语句把它右移一位,j 再向左继续查找;条件不成立时停止。循环结束后,右移过程在 j+1 处留下插入位置,程序把 key 写入该处。因此数据按到达时间升序排列,同一时间内按规格字母降序排列;加框语句的执行次数就是已有元素右移的总次数。
s=""
for i in range(n):
s=s+data[i][1]
return s排序完成后,程序按当前顺序取出每个元素中的规格字母 data[i][1],依次拼接到字符串 s 的末尾,最后返回拼接结果。
解题思路
外层循环逐个取出 data[i] 作为 key,内层循环从已有序部分的末端向左寻找插入位置,并把不符合顺序的元素依次右移,最后执行 data[j+1]=key。这是插入排序的典型结构。
按外层循环逐轮插入。加框语句每执行一次,就有一个已有元素向右移动:
i |
key |
本轮向右移动的已有元素 | 次数 |
|---|---|---|---|
| 1 | 07:45,D |
07:45,A |
1 |
| 2 | 07:45,A |
无 | 0 |
| 3 | 07:47,C |
无 | 0 |
| 4 | 07:47,B |
无 | 0 |
| 5 | 07:45,B |
从右向左依次为 07:47,B、07:47,C、07:45,A、07:45,A |
4 |
| 6 | 07:47,C |
07:47,B |
1 |
7个元素的所有外层轮次都已列出,加框语句总执行次数为 1+4+1=6。
第(3)小题
pos = len(top)
if top[mid] >= cur
top[pos] = cur
程序分析
n = len(box)
top=[] #每个堆最下面的一个位置
top_idx=[]
prev=[-1]*nn为集装箱数量。top与top_idx初始为空,prev为每个集装箱预留一个值为-1的记录位置。各列表的含义需结合后续存入和读取的数据确定;题面top后的注释与后文操作有冲突,以下按实际程序分析。
for i in range(n):
cur = ord(box[i])-65
left,right = 0,len(top)
①
...循环按到港顺序逐个处理集装箱。ord(box[i])-65 把规格 A~F 转换为 0~5,规格越大,得到的 cur 越大。
left 和 right 分别从 0 与 len(top) 开始,后续将在这个范围内确定新集装箱应放入哪一堆。
while left < right:
mid = (left + right) // 2
②:
pos = mid
right = mid
else:
left=mid+1循环每次取中间位置 mid,再根据空②的判断缩小左右边界,属于对分查找。条件成立时先把 mid 记入 pos,再令 right = mid 继续向左查找;条件不成立时令 left = mid+1。因此,这段代码要找的是满足条件的最左位置。
if pos < len(top):
prev[i] = top_idx[pos]
③
top_idx[pos] = i
else:
top.append(cur)
top_idx.append(i)新建堆时,top追加规格编码cur,top_idx追加当前箱子的下标i,可据此确定两者分别记录各堆堆顶规格和堆顶下标。放入已有堆时,先把原堆顶下标存入prev[i],再把top_idx[pos]更新为i,因此prev[i]记录当前箱子下面相邻箱子的下标,-1表示下方没有箱子。
for i in range(len(top)):
pile = []
curr_idx = top_idx[i] # 从堆顶开始
while curr_idx != -1:
pile.append(box[curr_idx])
curr_idx = prev[curr_idx]
return len(top)程序从每一堆的 top_idx[i] 开始,根据 prev 中保存的下方集装箱下标逐层向下访问,直至遇到 -1,由此还原各堆的集装箱。最终 len(top) 就是建立的堆数。
填空分析
①
查找未命中时,需要进入新建堆的else分支。将pos初始值设为len(top),即可使pos < len(top)不成立;找到合适的堆后,循环中的pos = mid会记录其位置。初始top为空时也能直接新建第一堆。故填:
pos = len(top)
②
题目要求在堆顶规格不小于cur的堆中,选择堆顶规格最小的一堆。top需要按非降序保存堆顶规格,这样最左侧满足top[mid] >= cur的位置就是目标。条件成立时记录mid,并令right = mid向左查找;条件不成立时,该位置及其左侧规格均过小,应令left = mid+1。
空②包含if关键字,题面已经给出冒号,因此填:
if top[mid] >= cur
③
当前箱子放入第pos堆后成为新的堆顶,规格应更新为cur,故填:
top[pos] = cur
这一更新也维持了top的非降序:pos左侧各值都小于cur,右侧各值不小于原top[pos],也就不小于cur。若查找未命中,则已有各堆顶都小于cur,将cur追加到末尾仍然有序。因此从空列表开始,每轮都能继续进行对分查找。
第(1)小题
3
按到港顺序处理,每次选择堆顶规格不小于新箱、且堆顶规格最小的一堆;找不到时才新建堆。只需跟踪各堆当前堆顶,变化如下:
| 到港次序 | 新箱规格 | 各堆堆顶规格(按建堆顺序) |
|---|---|---|
| 1 | C | C |
| 2 | C | C |
| 3 | D | C、D |
| 4 | B | B、D |
| 5 | A | A、D |
| 6 | C | A、C |
| 7 | A | A、C |
| 8 | C | A、C |
| 9 | D | A、C、D |
| 10 | B | A、B、D |
| 11 | A | A、B、D |
例如,第6个箱子 C 到港时,不能放在堆顶为 A 的第1堆上,可放在堆顶为 D 的第2堆上;第9个箱子 D 到港时,已有堆顶分别为 A、C,均小于 D,因此必须新建第3堆。最终可得到三堆,按从底到顶的顺序分别为 [C,C,B,A,A,A]、[D,C,C,B]、[D]。
此外,第5、第6、第9个箱子的规格依次为 A、C、D,体积按到港顺序严格增大。任意两个都不能放在同一堆:后到的较大箱子既不能放在先到的小箱子上,也不能放到它的下方。因此至少需要3堆,而上述方案恰好使用3堆,最少堆数为3。
第(2)②小题
DBAACCB
共用程序分析见第(2)①小题。
按照前面的排序规则,先处理07:45到达的记录,再处理07:47到达的记录;同一到达时间内,按规格字母从大到小排列。
| 到达时间 | 原有规格 | 排序后的规格顺序 |
|---|---|---|
| 07:45 | A、D、A、B | D、B、A、A |
| 07:47 | C、B、C | C、C、B |
最后一个 for 循环依次把排序后的规格字母拼接到 s 中,因此返回字符串 'DBAACCB'。
问题反馈
解析有疑问或显示异常?请先复制题目信息,再打开反馈表单填写。
题目编号:2026_05_G3_qiangjilianmeng_q015
