原SQL解法是把区块展开的思路,现在让他沿用第二部分的不展开思路。
请用第二部分的思路(不实际展开块)编写第一部分的解答程序,注意如下区别。1.文件是逐个块移动到空闲块,紧密放置。2.最右一个文件的块多于当前最左空闲块时,顺序填充到最左空闲块右边的空闲块,以此类推。停止移动条件是最右文件块左边无空闲块,移动完成后右边一定是连续的空闲块
结果不对,应该是没处理好一个空闲区块填充多个文件的问题。
继续提示
程序计算结果偏小,修改填充思路为从左到右,先计算第一个文件块chksum,然后模拟逐个最右文件块填入空闲块,填充某空闲区块(标记的长度>0)的单个块即计算chksum,一个区块多长,就计算多少次,跳到下个空闲区块之前,先计算中间间隔的文件块chksum,直到没有文件块可读。数据结构可以统一为bs be,用下标的奇偶性判断文件还是空闲区块,算的过程不用修改已填充部分,只要用一个指针记录右侧消除掉的文件fid 最后位置,按此思路改写
这次结果偏大,经过调试,发现循环轮数过多。
继续提示
算得多了,增加一个停止条件,当前填充位置已经是当前文件左邻空闲区块,下一个文件不能回绕到区块左侧, 只给出增加这个的代码段,不做别的
终于对了。完成的代码如下:
# Standard Library
import pathlib
def get_input(filename: str) -> list[str]:
"""
Takes a filename and returns a list of lines from the file
"""
output = []
file = pathlib.Path(filename)
with open(file) as f:
for line in f:
tmp_line = line.strip()
output.append(tmp_line)
return output
def solve_part1():
import sys
data = get_input("2409-input.txt")[0] #sys.stdin.read().strip()
# 1. 解析得到统一的 blocks 列表
bs, be = [], []
pos = 0
is_file = True
file_id = 0
for ch in data:
length = int(ch)
bs.append(pos)
be.append(pos + length - 1)
pos += length
is_file = not is_file
n_blocks = len(bs)
#print(bs,be)
# 2. 准备文件ID映射:偶数下标是文件,分配文件ID
file_ids = []
fid = 0
for i in range(n_blocks):
if i % 2 == 0: # 文件
file_ids.append(fid)
fid += 1
else: # 空闲区
file_ids.append(-1)
#print(file_ids)
# 3. 模拟移动并计算校验和
checksum = 0
current_pos = 0 # 当前计算位置
right_file_ptr = n_blocks - 1 # 指向最右的文件块(用于填充)
# 找到初始最右的文件块(最后一个偶数下标)
while right_file_ptr >= 0 and right_file_ptr % 2 != 0:
right_file_ptr -= 1
flag=0
for i in range(n_blocks):
start, end = bs[i], be[i]
if i % 2 == 0: # 文件块
# 计算这个文件的所有块
for pos in range(start, end + 1):
checksum += pos * file_ids[i]
#if i==2:print(pos,file_ids[i],"---")
current_pos = end + 1
else: # 空闲区
# 逐个填充这个空闲区的每个位置
for pos in range(start, end + 1):
# 检查是否还有文件块可填充
while right_file_ptr >= 0:
right_start, right_end = bs[right_file_ptr], be[right_file_ptr]
if right_end >= right_start: # 这个文件还有块
# 停止条件:当前填充位置已经是当前文件左邻空闲区块
if pos >= right_start:
# 下一个文件不能回绕到区块左侧,停止填充
flag=1;break
# 填充最右块到当前位置
checksum += pos * file_ids[right_file_ptr]
# 消耗掉这个文件的最右块
be[right_file_ptr] -= 1
break
else:
# 这个文件用完了,找前一个文件
right_file_ptr -= 2
# 跳过空闲区,找文件
while right_file_ptr >= 0 and right_file_ptr % 2 != 0:
right_file_ptr -= 1
else:
# 没有文件块可填充了,退出
break
if flag==1:break
current_pos = end + 1
#print(checksum)
# 检查是否所有文件块都已用完
if right_file_ptr < 0 or flag==1:
break
print(checksum)
if __name__ == "__main__":
solve_part1()
比SQL版本快了几倍
time python3 2409part1.py
6340197768906
real 0m0.087s
user 0m0.052s
sys 0m0.004s
time ./duckdb150 -c ".read 2409fastcode.txt"
┌─────────────────┐
│ chksum │
│ int128 │
├─────────────────┤
│ 6340197768906 │
│ (6.34 trillion) │
└─────────────────┘
real 0m0.877s
user 0m0.628s
sys 0m0.156s


被折叠的 条评论
为什么被折叠?



