利用Duckdb求解Advent of Code 2022第3题 背包重组

编程达人挑战赛·第4期 10w+人浏览 371人参与

原题地址:https://adventofcode.com/2022/day/3

第 3 天:背包重组

一个精灵负责一项重要工作:为丛林之旅将所有物资装入背包。不幸的是,那个精灵没有完全遵循打包说明,所以现在需要重新整理一些物品。

每个背包有两个大隔层。给定类型的所有物品应该恰好放入两个隔层中的一个。负责打包的精灵在每个背包中恰好有一种物品类型没有遵守这条规则。

精灵们已经列出了每个背包中当前所有的物品(你的谜题输入),但他们需要你帮忙找出错误。每种物品类型由一个单一的小写或大写字母标识(即,aA 指的是不同类型的物品)。

每个背包的物品列表以单行上的所有字符形式给出。一个给定的背包的两个隔层中总是有相同数量的物品,因此字符的前一半代表第一个隔层中的物品,字符的后一半代表第二个隔层中的物品。

例如,假设你有来自六个背包的以下内容列表:

vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw
  • 第一个背包包含物品 vJrwpWtwJgWrhcsFMMfFFhFp,这意味着它的第一个隔层包含物品 vJrwpWtwJgWr,而第二个隔层包含物品 hcsFMMfFFhFp。在两个隔层中都出现的唯一物品类型是小写字母 p
  • 第二个背包的隔层包含 jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL。在两个隔层中都出现的唯一物品类型是大写字母 L
  • 第三个背包的隔层包含 PmmdzqPrVvPwwTWBwg;唯一的共同物品类型是大写字母 P
  • 第四个背包的隔层只共享物品类型 v
  • 第五个背包的隔层只共享物品类型 t
  • 第六个背包的隔层只共享物品类型 s

为了帮助确定物品重新整理的优先级,每种物品类型都可以转换为一个优先级:

  • 小写物品类型 az 的优先级为 1 到 26。
  • 大写物品类型 AZ 的优先级为 27 到 52。

在上面的例子中,每个背包的两个隔层中都出现的物品类型的优先级分别是 16 §, 38 (L), 42 §, 22 (v), 20 (t), 和 19 (s);这些值的总和是 157。

找出每个背包的两个隔层中都出现的物品类型。这些物品类型的优先级之和是多少?

问题分析:
就是找出每行字符串左右两半中唯一的公共字符,这用取两边包含字符的交集即可,用数组或表的行都能实现,数组更简单,有现成的array_intersect函数,少一道步骤。
代码如下

with t as(select 'vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw' t),
b as(select unnest(string_split(t,chr(10)))b,substr(b,1,length(b)//2)L,substr(b,1+length(b)//2) R from t),
c as(select row_number()over()rn,array_intersect(string_split(l,''),string_split(r,''))[1] l from b)
select sum(case when l between 'a' and 'z' then ascii(l)-ascii('a')+1 else ascii(l)-ascii('A')+27 end) from c;

第二部分说,每三行归为1组,然后在一组中找到在三行中都出现的唯一字符,还是第一部分一样的思路,只不过这次是3行取交集。
代码如下:

with t as(select 'vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw' t),
b as(select row_number()over()rn,b from(select unnest(string_split(t,chr(10)))b from t)),
b0 as(select (rn-1)//3 gn,b from b where (rn-1)%3 =0), 
b1 as(select (rn-1)//3 gn,b from b where (rn-1)%3 =1), 
b2 as(select (rn-1)//3 gn,b from b where (rn-1)%3 =2), 
c as(select b0.gn, array_intersect(array_intersect(string_split(b0.b,''), string_split(b1.b,'')), string_split(b2.b,''))[1] l from b0, b1, b2 where b0.gn=b1.gn and b1.gn=b2.gn)
select sum(case when l between 'a' and 'z' then ascii(l)-ascii('a')+1 else ascii(l)-ascii('A')+27 end) from c;

思路是用行号减一除以3取整得到组号,然后就和第一部分一样了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值