当前位置: 首页 > news >正文

利用DeepSeek辅助DuckDB SQL求解Advent of Code 2025第10题 电子工厂

前期嫌SQL处理麻烦和性能不足,用python做过一个,
最近看到clickhouse微信公众号文章用纯 SQL 硬刚 Advent of Code?ClickHouse 把「不可能」变成了 12 天的现实。
看到了希望,所以用DuckDB SQL重新做过。

第一部分格式转换代码如下,都是自己完成的:

withrecursive tas(select'[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7} [...#.] (0,2,3,4) (2,3) (0,4) (0,1,2) (1,2,3,4) {7,5,12,7,2} [.###.#] (0,1,2,3,4) (0,3,4) (0,1,2,4,5) (1,2) {10,11,11,5,10,5}'t),bas(selectrow_number()over()rn,reverse(substr(b,2,instr(b,']')-2))b1,--信号灯字符串,格式.##.,注意要翻转字符串substr(b,instr(b,']')+2,instr(b,'{')-3-instr(b,']'))b2,--按钮字符串,格式(3) (1,3) (2) (2,3) (0,2) (0,1)substr(b,instr(b,'{')+1,instr(b,'}')-1-instr(b,'{'))b3,--伏特字符串,格式3,5,4,7translate(b1,'#.','10')::bit::intb1a,--转二进制位再转整数list_reduce([0]||string_split(unnest(string_split(replace(replace(b2,')',''),'(',''),' ')),',')::int[],lambda x,y :(x+(1<<y)))b2a,--按钮转成整数列表string_split(b3,',')::int[]b3a,from(selectunnest(string_split(t,chr(10)))bfromt)),das(selectrn,b1a,array_agg(b2a)a,b3afrombgroupbyall)fromdorderbyrn;

示例数据子查询d的结果如下

┌───────┬───────┬──────────────────────┬────────────────────────┐ │ rn │ b1a │ a │ b3a │ │ int64 │ int32 │ int32[] │ int32[] │ ├───────┼───────┼──────────────────────┼────────────────────────┤ │ 1 │ 6 │ [8, 10, 4, 12, 5, 3] │ [3, 5, 4, 7] │ │ 2 │ 8 │ [29, 12, 17, 7, 30] │ [7, 5, 12, 7, 2] │ │ 3 │ 46 │ [31, 25, 55, 6] │ [10, 11, 11, 5, 10, 5] │ └───────┴───────┴──────────────────────┴────────────────────────┘

一开始没注意信号灯字符串从左到右是从低位到高位,没做翻转,导致算错了b1a。

┌───────┬───────┬──────────────────────┬────────────────────────┐ │ rn │ b1a │ a │ b3a │ │ int64 │ int32 │ int32[] │ int32[] │ ├───────┼───────┼──────────────────────┼────────────────────────┤ │ 1 │ 6 │ [8, 10, 4, 12, 5, 3] │ [3, 5, 4, 7] │ │ 2 │ 2 │ [29, 12, 17, 7, 30] │ [7, 5, 12, 7, 2] │ │ 3 │ 29 │ [31, 25, 55, 6] │ [10, 11, 11, 5, 10, 5] │ └───────┴───────┴──────────────────────┴────────────────────────┘

DeepSeek辅助完成将每行按钮的各种组合求出。

我有一个数组a,包含n个元素,请用duckdb语法编写一句SQL,输出数组a的全部子集,比如[1,3]输出[],[1],[3],[1,3],

可以使用 DuckDB 的UNNEST配合WITH RECURSIVE递归生成子集。以下是 SQL 语句:

WITHRECURSIVE subsetsAS(-- 初始:空子集SELECT[]ASsubset,1ASlevelUNIONALL-- 递归:逐个添加元素SELECTarray_append(subset,a.val)ASsubset,level+1ASlevelFROMsubsets,UNNEST([1,3])WITHORDINALITYASa(val,idx)WHEREa.idx>=level)SELECTsubsetFROMsubsetsORDERBYcardinality(subset),subset;

如果不需要递归,也可以直接使用GENERATE_SERIES配合位运算:

WITHarrAS(SELECT[1,3]ASa)SELECT(SELECTarray_agg(a[i])FROMgenerate_series(1,array_length(a))ASiWHERE(bitpos>>(i-1))&1=1)ASsubsetFROMarr,generate_series(0,(1<<array_length(a))-1)ASbits(bitpos);

两种方法都可以输出所有子集:

  • []
  • [1]
  • [3]
  • [1, 3]

你可以根据 DuckDB 的版本和性能需求选择合适的方法。第一种递归方法更直观,第二种位运算方法通常性能更好。

我选的是第二种,如下语句把每种组合的两两异或结果算出,然后与要求的数比较。

,sas(SELECTrn,bitpos,b1a,(SELECTarray_agg(a[i])FROMgenerate_series(1,array_length(a))t(i)WHERE(bitpos>>(i-1))&1=1)ASsubsetFROMd,generate_series(1,(1<<array_length(a))-1)ASbits(bitpos))selectrn,b1a,bitpos,subset,bit_count(bitpos)fromswherelist_reduce(subset,lambda x,y :xor(x,y))=b1aorderbyrn,5;

结果如下,按压次数最少的组合已标记。

┌───────┬───────┬────────┬──────────────────┬───────────────────┐ │ rn │ b1a │ bitpos │ subset │ bit_count(bitpos) │ │ int64 │ int32 │ int64 │ int32[] │ int8 │ ├───────┼───────┼────────┼──────────────────┼───────────────────┤ │ 1 │ 6 │ 48 │ [5, 3] │ 2 │<-- │ 1 │ 6 │ 10 │ [10, 12] │ 2 │ │ 1 │ 6 │ 7 │ [8, 10, 4] │ 3 │ │ 1 │ 6 │ 61 │ [8, 4, 12, 5, 3] │ 5 │ │ 2 │ 8 │ 28 │ [17, 7, 30] │ 3 │<-- │ 2 │ 8 │ 27 │ [29, 12, 7, 30] │ 4 │ │ 3 │ 46 │ 6 │ [25, 55] │ 2 │<-- │ 3 │ 46 │ 13 │ [31, 55, 6] │ 3 │ └───────┴───────┴────────┴──────────────────┴───────────────────┘

最后按原始行号分组求最小值,再加总。

selectsum(minstep)from(selectrn,min(bit_count(bitpos))minstep--按压组合二进制数的1的个数就是按压次数fromswherelist_reduce(subset,lambda x,y :xor(x,y))=b1agroupbyrn);

对于示例数据,结果如下,和题目给出的一致

┌──────────────┐ │ sum(minstep) │ │ int128 │ ├──────────────┤ │ 7 │ └──────────────┘

对于我的正式测试数据,结果和用时如下,不算太快

┌──────────────┐ │ sum(minstep) │ │ int128 │ ├──────────────┤ │ 527 │ └──────────────┘ Run Time (s): real 0.328 user 1.588000 sys 0.052000

这里发现Advent of Code的测试题库也是有重复的,这个结果和clickhouse公众号的一致。

理论上本题用递归更合适,因为要求最少按压次数,只要求出一个解就可以退出迭代了,而全组合是穷举。第二部分题目的数据量不可能用穷举解决。

再用第一种方法试做一遍,直接使用DeepSeek的语句报错

Binder Error: Cardinality can only operate on MAPs

去掉cardinality函数输出如下,有多余的[3, 3]

┌─────────┐ │ subset │ │ int32[] │ ├─────────┤ │ [] │ │ [1] │ │ [3] │ │ [1, 3] │ │ [3, 3] │ └─────────┘

需要改成如下,规定后加的元素索引必须要大于前面最后一个的索引,不允许重复使用,才能得到正确结果。

WITHRECURSIVE subsetsAS(-- 初始:空子集SELECT[]ASsubset,1ASlevel,0lastidxUNIONALL-- 递归:逐个添加元素SELECTarray_append(subset,a.val)ASsubset,level+1ASlevel,idxFROMsubsets,UNNEST([1,2,3])WITHORDINALITYASa(val,idx)WHEREa.idx>lastidx)SELECTsubsetFROMsubsets;┌───────────┐ │ subset │ │ int32[]│ ├───────────┤ │[]│ │[1]│ │[2]│ │[3]│ │[1,2]│ │[1,3]│ │[2,3]│ │[1,2,3]│ └───────────┘

再结合本题的业务逻辑,找到就不再迭代。

,subsetsAS(-- 初始:空子集SELECTrn,[]ss,0xor_val,0ASlevel,0lastidxfromdUNIONALL-- 递归:逐个添加元素SELECTs.rn,ss||[a.val],xor(xor_val,a.val),level+1ASlevel,idxFROMsubsets s,d,unnest(a)WITHORDINALITYASa(val,idx)WHEREa.idx>lastidxands.rn=d.rnandnotexists(select1fromd d1wherexor_val=b1aands.rn=d1.rn))SELECTs.rn,xor_val,level,ssFROMsubsets s,d d1wherexor_val=b1aands.rn=d1.rnorderbys.rn,level;┌───────┬─────────┬───────┬──────────────────┐ │ rn │ xor_val │level│ ss │ │ int64 │ int32 │ int32 │ int32[]│ ├───────┼─────────┼───────┼──────────────────┤ │162[5,3]<--162[10,12]│ │163[8,10,4]│ │165[8,4,12,5,3]│ │283[17,7,30]<--284[29,12,7,30]│ │3462[25,55]<--3463[31,55,6]│ └───────┴─────────┴───────┴──────────────────┘

和前面穷举的结果完全一致。按原始行号分组求最小值,再加总。

,ras(SELECTs.rn,xor_val,level,ssFROMsubsets s,d d1wherexor_val=b1aands.rn=d1.rnorderbys.rn,level)selectsum(minl)from(selectrn,min(level)minlfromrgroupbyrn);┌───────────┐ │sum(minl)│ │ int128 │ ├───────────┤ │7│ └───────────┘

使用正式测试数据,用时反而更长

┌───────────┐ │ sum(minl) │ │ int128 │ ├───────────┤ │ 527 │ └───────────┘ Run Time (s): real 0.633 user 1.632000 sys 0.312000

尝试去掉不必要的ss,将a和b1a的数据带入subset查询,减少一次表连接,仍然不如穷举,可能是递归中not exists检查还是做了表连接的原因。

Run Time (s): real 0.472 user 1.252000 sys 0.152000

最后加了一个found标记,用分析函数找出当前rn中是否有找到的,消除not exists检查,快了。

,subsetsAS(-- 初始:空子集SELECTrn,a,b1a,0found,0xor_val,0ASlevel,0lastidxfromdUNIONALL-- 递归:逐个添加元素SELECTs.rn,s.a,s.b1a,max(s.xor_val=s.b1a)over(partitionbys.rn),xor(xor_val,a.val),level+1ASlevel,idxFROMsubsets s,unnest(a)WITHORDINALITYASa(val,idx)WHEREa.idx>lastidxandnotfound),ras(SELECTs.rn,xor_val,levelFROMsubsets swherexor_val=b1aorderbys.rn,level)selectsum(minl)from(selectrn,min(level)minlfromrgroupbyrn);┌───────────┐ │sum(minl)│ │ int128 │ ├───────────┤ │527│ └───────────┘ RunTime(s):real0.236user0.608000sys0.152000

看了一下clickhouse第一部分的解法,也是穷举。

http://www.jsqmd.com/news/275237/

相关文章:

  • SSM286的旅游网站掌柜有礼vue
  • ARM Cortex-M 存储器系统详解
  • 阿里拿38K出来的大佬良心分享,熬夜整理10 万字详细Java面试笔记!
  • psql 中的流水线操作(PostgreSQL 18)
  • 深度测评8个AI论文写作软件,本科生轻松搞定毕业论文!
  • 汉字:世界语言之王的硬核底气,人类文明的天花板级存在
  • Win10调出运行界面
  • 【课程设计/毕业设计】基于Python的智能房价分析与预测系统基于django的城市房产价值的数据分析与预测系统的设计与实现【附源码、数据库、万字文档】
  • Spring Security整合JWT与Redis实现权限认证
  • 人类目前最难的前三个计算问题是什么?直接给你们问题和计算结果。你给问题,我给答案,其他人吃瓜!
  • 【课程设计/毕业设计】基于python房价预测系统的设计与实现机器学习的房子价值预测系统的设计与实现【附源码、数据库、万字文档】
  • SpringBoot + RabbitMQ + 事务状态机 实现电商订单超时自动关单
  • 微信立减金回收暗藏门道,别再让闲置优惠白白浪费! - 京顺回收
  • 【课程设计/毕业设计】基于hadoop的山东瓜果蔬菜分析系统【附源码、数据库、万字文档】
  • 说白了现在为了解决计算问题开发量子计算机。而现在量子计算机解决不了的我们的理论轻松可以解决
  • pytorch深度学习实战:从全连接神经网络到卷积神经网络
  • 冲刺金三银四!GitHub中文社区高热度的Java面试题被我整理好了!
  • 【毕业设计】基于hadoop的山东瓜果蔬菜分析系统(源码+文档+远程调试,全bao定制等)
  • 微信立减金回收暗藏门道,别再让闲置优惠白白浪费!
  • 关于yum、Red Hat与apt、Debian
  • 百乐满热水器维修电话:深圳用户必看!深圳百乐满售后联系方式与专业服务指南
  • 大数据毕设选题推荐:基于hadoop的山东瓜果蔬菜分析系统【附源码、mysql、文档、调试+代码讲解+全bao等】
  • SEO老手都踩过的坑:301和302重定向到底该用哪个?一文说透不翻
  • 大数据毕设选题推荐:基于django的二手房价格分析预测系统城市房产价值的数据分析与预测系统的设计与实现【附源码、mysql、文档、调试+代码讲解+全bao等】
  • 年终运维愁?塔能智慧照明让总结计划秒变“神助攻”!
  • Flink源码阅读:Kafka Connector
  • Jetson 磁盘加密学习笔记:从 LUKS/dm-crypt 到 APP/APP_ENC 与量产流程
  • AI写作知识体系:架构、理论与工程实践【高级版】
  • 计算机大数据毕设实战-基于hadoop的山东瓜果蔬菜分析系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 树的练习7--------LCR 052.递增顺序搜索树