原题地址:https://adventofcode.com/2022/day/3
第 3 天:背包重组
一个精灵负责一项重要工作:为丛林之旅将所有物资装入背包。不幸的是,那个精灵没有完全遵循打包说明,所以现在需要重新整理一些物品。
每个背包有两个大隔层。给定类型的所有物品应该恰好放入两个隔层中的一个。负责打包的精灵在每个背包中恰好有一种物品类型没有遵守这条规则。
精灵们已经列出了每个背包中当前所有的物品(你的谜题输入),但他们需要你帮忙找出错误。每种物品类型由一个单一的小写或大写字母标识(即,a 和 A 指的是不同类型的物品)。
每个背包的物品列表以单行上的所有字符形式给出。一个给定的背包的两个隔层中总是有相同数量的物品,因此字符的前一半代表第一个隔层中的物品,字符的后一半代表第二个隔层中的物品。
例如,假设你有来自六个背包的以下内容列表:
vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw
- 第一个背包包含物品
vJrwpWtwJgWrhcsFMMfFFhFp,这意味着它的第一个隔层包含物品vJrwpWtwJgWr,而第二个隔层包含物品hcsFMMfFFhFp。在两个隔层中都出现的唯一物品类型是小写字母p。 - 第二个背包的隔层包含
jqHRNqRjqzjGDLGL和rsFMfFZSrLrFZsSL。在两个隔层中都出现的唯一物品类型是大写字母L。 - 第三个背包的隔层包含
PmmdzqPrV和vPwwTWBwg;唯一的共同物品类型是大写字母P。 - 第四个背包的隔层只共享物品类型
v。 - 第五个背包的隔层只共享物品类型
t。 - 第六个背包的隔层只共享物品类型
s。
为了帮助确定物品重新整理的优先级,每种物品类型都可以转换为一个优先级:
- 小写物品类型
a到z的优先级为 1 到 26。 - 大写物品类型
A到Z的优先级为 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取整得到组号,然后就和第一部分一样了。

679

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



