Advent of Code

使用 python 编写, 没有整理代码, 所以非常乱(变量乱取名, 没有注释, 逻辑奇怪, 并非最佳实现)
可以使用 gpt 相关工具辅助查看

如果没有特意说明, 变量 aaa 统一存放所有原始字符串

今年的 ai 翻译工具好了很多 翻译的更容易懂了 许多

今年只有12题

第一题

https://adventofcode.com/2025/day/1

1题

钟表 一共100个刻度(0-99) 往左转或者往右转 n 个度数
刚好转到 0 的次数是多少
模拟即可

Details

counts = 0
now = 50
for line in aaa.splitlines():
    direction = line[0]
    steps = int(line[1:])
    if direction == 'L':
        now -= steps
    elif direction == 'R':
        now += steps
    
    now = (now + 100) % 100
    if now == 0:
        counts += 1

print(counts)

2题

在1题的基础上 变成旋转过程中 经过0的次数 (转到0也算)

继续模拟 注意有的会转超过一圈

Details

counts = 0
now = 50
for line in aaa.splitlines():
    is_zero_now = (now == 0)
    direction = line[0]
    steps = int(line[1:])

    cricles = steps // 100
    counts += cricles
    steps = steps % 100

    if direction == 'L':
        now -= steps
    elif direction == 'R':
        now += steps
    
    if not is_zero_now:
        if now <= 0:
            counts += 1
    
    if now >= 100:
        counts += 1

    now = (now + 100) % 100
    # if now == 0:
    #     counts += 1

print(counts)

第二题

https://adventofcode.com/2025/day/2

1题

给定范围 找到仅由重复两次的数序数字组成的任何 ID

Details

input_list = aaa.split(",")

ans = 0
for range_pair in input_list:
    start, end = map(int, range_pair.split("-"))
    for number in range(start, end + 1):
        str_number = str(number)
        if len(str_number) % 2 != 0:
            # if len(set(str_number)) == 1:
            #     ans += number
            continue
        else:
            mid = len(str_number) // 2
            first_half = str_number[:mid]
            second_half = str_number[mid:]
            if first_half == second_half:
                ans += number
                continue
print(ans)

2题

在1题的基础上 重复两次变成重复若干次

Details

input_list = aaa.split(",")

def get_factors(n: int) -> list:
    factors = []
    for i in range(2, int(sqrt(n)) + 1):
        if n % i == 0:
            factors.append([i, n // i])
            
    factors.append([1, n])
    return factors


ans = 0
for range_pair in input_list:
    start, end = map(int, range_pair.split("-"))
    for number in range(start, end + 1):
        str_number = str(number)
        if len(str_number) < 2:
            continue
            
        factors = get_factors(len(str_number))
        for f1, f2 in factors:
            if str_number[:f1] * f2 == str_number:
                # print(number)
                ans += number
                break
            if 1 not in [f1, f2]:
                if str_number[:f2] * f1 == str_number:
                    # print(number)
                    ans += number
                    break

print(ans)

第三题

https://adventofcode.com/2025/day/3

1题

给定一串数字 这些数字在里面取 相对位置固定的两个数字 来组成最大的数

Details

ans = 0
for line in aaa.split("\n"):
    max_left_num = int(line[0])
    max_left_index = 0
    for i, c in enumerate(line[1:-1]):
        if int(c) > max_left_num:
            max_left_num = int(c)
            max_left_index = i + 1
    max_right_num = int(line[-1])
    for j in range(len(line) - 2, max_left_index, -1):
        if int(line[j]) > max_right_num:
            max_right_num = int(line[j])
    
    ans += max_left_num * 10 + max_right_num

print(ans)

2题

在1题的基础上 取12个数字 组成最大的数

Details

ans = 0
n = 12
for line in aaa.split("\n"):
    dp = [[-1] * (n + 1) for _ in range(len(line) + 1)]
    dp[0][0] = 0
    for i in range(len(line)):
        for j in range(n + 1):
            if dp[i][j] == -1:
                continue
            # 不选
            dp[i + 1][j] = max(dp[i + 1][j], dp[i][j])
            # 选
            if j < n:
                dp[i + 1][j + 1] = max(dp[i + 1][j + 1], dp[i][j] * 10 + int(line[i]))
    ans += dp[len(line)][n]

print(ans)

第四题

https://adventofcode.com/2025/day/4

1题

给定一张图 标记所有东西的位置 找出 相邻八个位置中 满足一半或更多的位置是空的 有东西的数量

有点难描述 可以点进原文查看原题

Details

a = [list(line) for line in aaa.splitlines()]

for row in range(len(a)):
    for col in range(len(a[0])):
        # if a[row][col] == '.':
        pairs = []
        # 统计周围八个少于4
        for i in [-1, 0, 1]:
            for j in [-1, 0, 1]:
                if i == 0 and j == 0:
                    continue
                if 0 <= row + i < len(a) and 0 <= col + j < len(a[0]):
                    if a[row + i][col + j] == '@' or a[row + i][col + j] == 'x':
                        pairs.append((row + i, col + j))
        # 少于4个@ 则将@变成x
        if len(pairs) < 4 and a[row][col] == '@':
            # for i, j in pairs:
            #     a[i][j] = 'x'
            a[row][col] = 'x'

ans = 0
for row in range(len(a)):
    for col in range(len(a[0])):
        if a[row][col] == 'x':
            ans += 1

print(ans)

特别解法
可以将空的位置转换成0 有东西的位置转换成1 这样获得了一个矩阵
对他进行卷积 取值小于等于4的点即可 padding要是1

2题

在1题的基础上 找出来的位置都可以去掉变成空的 然后继续找

Details

a = [list(line) for line in aaa.splitlines()]
ans = 0
num_of_at = sum(row.count('@') for row in a)
temp_num_of_at = num_of_at
while True:
    for row in range(len(a)):
        for col in range(len(a[0])):
            pairs = []
            # 统计周围八个少于4
            for i in [-1, 0, 1]:
                for j in [-1, 0, 1]:
                    if i == 0 and j == 0:
                        continue
                    if 0 <= row + i < len(a) and 0 <= col + j < len(a[0]):
                        if a[row + i][col + j] == '@' or a[row + i][col + j] == 'x':
                            pairs.append((row + i, col + j))
            # 少于4个@ 则将@变成x
            if len(pairs) < 4 and a[row][col] == '@':
                a[row][col] = '.'
    new_num_of_at = sum(row.count('@') for row in a)
    if new_num_of_at == temp_num_of_at:
        break
    temp_num_of_at = new_num_of_at

ans = num_of_at - new_num_of_at 

print(ans)

相似的 也可以使用 1题的卷积思路

第五题

https://adventofcode.com/2025/day/5

1题

给定一个范围 给定一系列数字 找到所有在范围内的数

Details

fresh_ranges_text, vegtables_text = aaa.split("\n\n")

fresh_ranges = []
for line in fresh_ranges_text.strip().splitlines():
    start, end = map(int, line.split("-"))
    fresh_ranges.append((start, end))

ans = 0
for line in vegtables_text.strip().splitlines():
    iid = int(line)
    is_fresh = any(start <= iid <= end for start, end in fresh_ranges)
    ans += is_fresh

print(ans)

2题

在1题的基础上 一系列数字不需要使用
找到范围内有多少数字
需要合并区间

Details

fresh_ranges_text, vegtables_text = aaa.split("\n\n")

fresh_ranges = []
for line in fresh_ranges_text.strip().splitlines():
    start, end = map(int, line.split("-"))
    fresh_ranges.append((start, end))

# merge
fresh_ranges.sort()
merged_fresh = []
for start, end in fresh_ranges:
    if not merged_fresh or merged_fresh[-1][1] < start:
        merged_fresh.append((start, end))
    else:
        merged_fresh[-1] = (merged_fresh[-1][0], max(merged_fresh[-1][1], end))

ans = 0
for i, j in merged_fresh:
    ans += j - i + 1
print(ans)

第六题

https://adventofcode.com/2025/day/6

1题

竖着的加法乘法计算器

Details

a = aaa.splitlines()
b = [list(map(int, line.split())) for line in a if line and not line.startswith('*')]
c = [line.split() for line in a[-1]]

# 去除split后的空字符串
b = [[num for num in line if num] for line in b]
c = [op[0] for op in c if op]


result = 0
for i in range(len(b[0])):
    match c[i]:
        case '+':
            result += b[0][i] + b[1][i] + b[2][i] + b[3][i]
        case '*':
            result += b[0][i] * b[1][i] * b[2][i] * b[3][i]

print(result)

2题

竖着的 按位的 加减乘除计算器

Details

ops = aaa.splitlines()[-1]
ops = [op for op in ops.split(" ") if op]
total_lines = aaa.splitlines()
lines = total_lines[:-1]

width = len(lines[0])
height = len(lines)

ans = 0
temp = []
number = 0

for pos_x in range(width - 1, -1, -1):
    for pos_y in range(height + 1):
        char = total_lines[pos_y][pos_x]
        if pos_y == height:
            temp.append(number)
            number = 0
        if char == " " and pos_y != height:
            continue
        elif char in '+*':
            if char == '+':
                ans += sum(temp)
            if char == '*':
                prod = 1
                for t in temp:
                    if t != 0:
                        prod *= t
                ans += prod
            temp = []
        else:
            if char == " ":
                continue
            number *= 10
            number += int(char)

print(ans)

第七题

https://adventofcode.com/2025/day/7

1题

图 发射一道激光往下 遇到 ^分成左右两股激光继续向下
会分裂多少次

Details

a = [list(line) for line in aaa.splitlines()]
width = len(a[0])
height = len(a)

pos_s_x, pos_s_y = aaa.index('S'), 0

deque = [(pos_s_x, pos_s_y)]
ans = 0
visited = set()
for i in deque:
    x, y = i
    if y + 1 >= height:
        continue
    if a[y + 1][x] == '^':
        if y + 1 < height:
            if (x + 1, y + 1) not in visited:
                deque.append((x + 1, y + 1))
                visited.add((x + 1, y + 1))
            if (x - 1, y + 1) not in visited:
                deque.append((x - 1, y + 1))
                visited.add((x - 1, y + 1))
            ans += 1
    elif a[y + 1][x] == '.':
        if y + 1 < height:
            if (x, y + 1) not in visited:
                deque.append((x, y + 1))
                visited.add((x, y + 1))
    

print(len(visited))
print(ans)

2题

在1题的基础上 有多少条不同路径的光线 (到达同一个目的地的不同路径光线 也需要计算)

Details

a = [list(line) for line in aaa.splitlines()]
width = len(a[0])
height = len(a)

pos_s_x, pos_s_y = aaa.index('S'), 0

cache = {}

def dfs(x, y):
    if y + 1 >= height or x < 0 or x >= width:
        return 0
    if (x, y) in cache:
        return cache[(x, y)]
    
    if a[y + 1][x] == '^':
        result = dfs(x + 1, y + 1) + dfs(x - 1, y + 1) + 1
    elif a[y + 1][x] == '.':
        result = dfs(x, y + 1)
    else:
        result = 0
    
    cache[(x, y)] = result
    return result
    
print(dfs(pos_s_x, pos_s_y) + 1)

第八题

https://adventofcode.com/2025/day/8

1题

给定若干个x,y,z坐标的点 连接最近的1000个点 问 有多少簇

Details

a = aaa.split('\n')
a = [list(map(int, i.split(','))) for i in a]

def distance(x1, y1, z1, x2, y2, z2):
    return ((x1 - x2) ** 2 + (y1 - y2) ** 2 + (z1 - z2) ** 2) ** 0.5

distances = []
for i in range(len(a)):
    for j in range(i + 1, len(a)):
        dist = distance(a[i][0], a[i][1], a[i][2], a[j][0], a[j][1], a[j][2])
        distances.append((dist, i, j))

distances.sort(key=lambda x: x[0])

needed_distances = distances[:1000]

# 邻接表
graph = {i: [] for i in range(len(a))}
for dist, i, j in needed_distances:
    graph[i].append((j, dist))
    graph[j].append((i, dist))

# dfs 遍历所有群组 获取所有群组节点数量
visited = [False] * len(a)
def dfs(node):
    stack = [node]
    size = 0
    while stack:
        current = stack.pop()
        if not visited[current]:
            visited[current] = True
            size += 1
            for neighbor, _ in graph[current]:
                if not visited[neighbor]:
                    stack.append(neighbor)
    return size
group_sizes = []
for i in range(len(a)):
    if not visited[i]:
        group_size = dfs(i)
        group_sizes.append(group_size)
group_sizes.sort()
print(group_sizes)

2题

最小生成树
一点一点连接最近的两个点 最后连接的两个点是哪两个点

Details

a = aaa.split('\n')
a = [list(map(int, i.split(','))) for i in a]

def distance(x1, y1, z1, x2, y2, z2):
    return ((x1 - x2) ** 2 + (y1 - y2) ** 2 + (z1 - z2) ** 2) ** 0.5

distances = []
for i in range(len(a)):
    for j in range(i + 1, len(a)):
        dist = distance(a[i][0], a[i][1], a[i][2], a[j][0], a[j][1], a[j][2])
        distances.append((dist, i, j))

distances.sort(key=lambda x: x[0])

# 构建最小生成树
parent = [i for i in range(len(a))]
num_components = len(a)
def find(x):
    if parent[x] != x:
        parent[x] = find(parent[x])
    return parent[x]

def union(x, y):
    rootX = find(x)
    rootY = find(y)
    if rootX != rootY:
        parent[rootY] = rootX
        return True
    return False

mst_edges = []
for dist, i, j in distances:
    if union(i, j):
        mst_edges.append((dist, i, j))
        num_components -= 1
        if num_components == 1:
            print("i, j, dist:", i, j, dist)
            break

# 获取 i, j 对应的点坐标
point_i = a[i]
point_j = a[j]

print("Point i:", point_i)
print("Point j:", point_j)

第九题

https://adventofcode.com/2025/day/9

1题

给定若干个x y 坐标点 找到最大的 以这两个点作为对角的 矩形

Details

a = [(int(x), int(y)) for x, y in (line.split(",") for line in aaa.split("\n"))]

def cal_space(x1, y1, x2, y2):
    return (abs(x1 - x2) + 1) * (abs(y1 - y2) + 1)

ans = 0
for i in range(len(a) - 1):
    for j in range(i + 1, len(a)):
        x1, y1 = a[i]
        x2, y2 = a[j]
        space = cal_space(x1, y1, x2, y2)
        if space > ans:
            ans = space

print(ans)

2题

在1题的基础上 上一个点 的x或者y与下一个点的x或者y相同 由此绕出了一个形状 需要找到最大的 在这个形状中的 以这两个点作为对角的矩形

检查这个矩形在不在这个形状里

Details

a = [(int(x), int(y)) for x, y in (line.split(",") for line in aaa.split("\n"))]

def cal_space(x1, y1, x2, y2):
    return (abs(x1 - x2) + 1) * (abs(y1 - y2) + 1)

def check(edges, x1, y1, x2, y2) -> bool:
    min_x = min(x1, x2)
    max_x = max(x1, x2)
    min_y = min(y1, y2)
    max_y = max(y1, y2)
    mid_x = (x1 + x2) / 2
    mid_y = (y1 + y2) / 2

    def ray_cast(midpoint, edges):
        count = 0
        mx, my = midpoint
        for (x3, y3), (x4, y4) in edges:
            if x3 > mx and x4 > mx:
                if min(y3, y4) <= my < max(y3, y4):
                    count += 1
        return count % 2 == 1
    
    if not ray_cast((mid_x, mid_y), edges):
        return False

    for (x3, y3), (x4, y4) in edges:
        if x3 == x4:
            if min_x < x3 < max_x:
                edge_min_y = min(y3, y4)
                edge_max_y = max(y3, y4)
                if not (edge_max_y <= min_y or edge_min_y >= max_y):
                    return False
                
        elif y3 == y4:
            if min_y < y3 < max_y:
                edge_min_x = min(x3, x4)
                edge_max_x = max(x3, x4)
                if not (edge_max_x <= min_x or edge_min_x >= max_x):
                    return False
    return True


edges = []
for i in range(0, len(a) - 1):
    edges.append((a[i], a[i + 1]))

edges.append((a[-1], a[0]))

ans = 0
for i in range(0, len(a) - 1):
    for j in range(i + 1, len(a)):
        x1, y1 = a[i]
        x2, y2 = a[j]
        space = cal_space(x1, y1, x2, y2)
        if space <= ans:
            continue
        if check(edges, x1, y1, x2, y2):
            ans = space

print(ans)

第十题

https://adventofcode.com/2025/day/10

1题

给定 灯最终需要到达的状态
给定 每个按钮 按下按钮后 各个灯的变化
给定 计数器 (第一题 用不到)

求 将完全关闭的灯泡 切换到 最终需要到达的状态需要按多少次

Details

import re

a = aaa.splitlines()
t = []
for i in a:
    lights = re.findall(r'\[(.*?)\]', i)[0]
    steps = re.findall(r'\((.*?)\)', i)
    joltages = re.findall(r'\{(.*?)\}', i)[0]
    steps = [list(map(int, s.split(','))) if s else [] for s in steps]
    joltages = list(map(int, joltages.split(',')))
    lights_len = len(lights)
    t.append((lights, lights_len, steps, joltages))

ans = 0
for lights, lights_len, steps, joltages in t:
    # 最少操作数让所有灯满足lights中的要求 不需要考虑电压
    dp = {0: 0}  # 状态压缩dp
    for step in steps:
        next_dp = {}
        for state, cnt in dp.items():
            # 不按
            if state not in next_dp or next_dp[state] > cnt:
                next_dp[state] = cnt
            # 按
            next_state = state
            for s in step:
                next_state ^= (1 << s)
            if next_state not in next_dp or next_dp[next_state] > cnt + 1:
                next_dp[next_state] = cnt + 1
        dp = next_dp
    final_state = 0
    for i in range(lights_len):
        if lights[i] == '#':
            final_state |= (1 << i)
    ans += dp[final_state]

print(ans)

2题

题意转换为
给定 灯最终需要到达的状态 (第二题用不到)
给定 每个按钮 按下按钮后 各个灯电压加一
给定 电压计数器

达到给定电压(超过也行) 需要按多少次

这是一题 带有约束的 正整数线性方程求解 直接调用库求解即可

Details

import re

a = aaa.splitlines()
t = []
for i in a:
    lights = re.findall(r'\[(.*?)\]', i)[0]
    steps = re.findall(r'\((.*?)\)', i)
    joltages = re.findall(r'\{(.*?)\}', i)[0]
    steps = [list(map(int, s.split(','))) if s else [] for s in steps]
    joltages = list(map(int, joltages.split(',')))
    lights_len = len(lights)
    t.append((lights, lights_len, steps, joltages))

import z3

def solve(lights, lights_len, steps, joltages):
    # 设 steps 列表中的第 i 个元素为xi 约束: xi大于等于0 且整数
    # sum(Aji * xi) = bj
    # Aji = 1 表示第i个按钮可以控制到第j个灯, 也就是可以增加第j个灯的电压
    # xi 表示第i个按钮按下的次数
    # bj 表示第j个灯的目标电压
    # 求解 minimize sum(xi)
    s = z3.Solver()
    x = [z3.Int(f'x{i}') for i in range(len(steps))]
    for i in range(len(steps)):
        s.add(x[i] >= 0)
    for j in range(lights_len):
        coeffs = []
        for i in range(len(steps)):
            if j in steps[i]:
                coeffs.append(x[i])
        s.add(z3.Sum(coeffs) == joltages[j])
    obj = z3.Sum(x)
    h = z3.Optimize()
    h.add(s.assertions())
    h.minimize(obj)
    if h.check() == z3.sat:
        m = h.model()
        res = [m.evaluate(x[i]).as_long() for i in range(len(steps))]
        return res
    else:
        return [-1] * len(steps)
    
results = []
for lights, lights_len, steps, joltages in t:
    res = solve(lights, lights_len, steps, joltages)
    results.append(res)
for res in results:
    print(' '.join(map(str, res)))

ans = sum(sum(r) for r in results)
print(ans)

第十一题

https://adventofcode.com/2025/day/11

1题

给定 若干个映射 f(a) -> b
b不一定只有一个 找到从 特定字符开始 到结束字符的 每条路径

Details

a = {}
for i in aaa.splitlines():
    p, q = i.split(": ")
    a[p] = q.split(" ")


def dfs(t):
    if t == 'out':
        return 0
    nt = a[t]
    b = 0
    for i in nt:
        b += dfs(i)
    return b + len(nt) - 1

print(dfs('you') + 1)

2题

在1题的基础上 特定字符换了一下 且需要同时经过 某两个字符(顺序无关)

Details

import functools

a = {}
for i in aaa.splitlines():
    p, q = i.split(": ")
    a[p] = q.split(" ")


@functools.lru_cache(None)
def dfs(t, visited_dac, visited_fft):
    if t == 'dac':
        visited_dac = True
    if t == 'fft':
        visited_fft = True
    if t == 'out':
        if visited_dac and visited_fft:
            return 1, visited_dac, visited_fft
        else:
            return 0, visited_dac, visited_fft
    nt = a[t]
    b = 0
    for i in nt:
        b += dfs(i, visited_dac, visited_fft)[0]
    return b, visited_dac, visited_fft

print(dfs('svr', False, False))

路线一下就不是同一个数量级的

第十二题

https://adventofcode.com/2025/day/12

只有一题

建议看原文

给定特定形状 给定一个二维箱子 大小有限 可以旋转 以及见缝插针

问这些东西能不能放进去

这是一题整蛊题 正常来说算法实现非常困难

Details

all_data = aaa.split('\n\n')
t = all_data[:-1]
gifts = []
for i in t:
    gift = []
    for line in i.split('\n'):
        if ':' in line:
            continue
        gift.append(line)
    gifts.append(gift)

print(gifts)
gift_area = []
for i in gifts:
    area_num = 0
    for line in i:
        area_num += line.count("#")
    gift_area.append(area_num)

print(gift_area)

ans = 0
a = all_data[-1]
for line in a.splitlines():
    region, gift_nums_str = line.split(': ')
    wide_, long_ = region.split('x')
    gift_nums = gift_nums_str.split(" ")
    all_area = int(wide_) * int(long_)
    needed_area = 0
    for i in range(len(gift_nums)):
        needed_area += int(gift_nums[i]) * gift_area[i]
    if needed_area <= all_area:
        ans += 1

print(ans)

仅需检测面积即可

转载无需注明出处