原文:
towardsdatascience.com/im-doing-the-advent-of-code-2024-in-python-day-1-8a9ea6ca6d3f
编程挑战赛是一套每年 12 月 1 日至 25 日发布的 25 个编程谜题。埃里克·瓦斯特尔(Eric Wastl)受到圣诞日历的启发,自 2015 年以来一直在组织编程挑战赛。
这是我第一次参加,我完成了前 4 个谜题。我决定为每个谜题写一篇博客文章,解释我的方法和解决问题的方案。
如我之前从参加过编程挑战赛的人那里听说和读到的那样,在 15 个谜题之后(通常更早)会变得非常困难。
所以我不确定我是否能到达终点,但我会尽力而为。无论如何,这将是在数据结构和算法方面的一次很好的实践。解决谜题和收集星星也很有趣。
这些谜题可以使用任何编程语言来解决。我将使用 Python,因为 1) 我在工作中主要使用 Python(我的另一个选择是 R)2) 我可以用 Python 触及更广泛的受众。
在我开始之前还有最后一件事:我的解决方案可能不是最好的或最有效率的。如果你知道更好的解决方案或有任何改进建议,请请在评论中分享。
在撰写本文时,前 6 个谜题已经发布,每个谜题都有两部分。我已经完成了第一个谜题的两部分,以及第二个、第三个和第四个谜题的第一部分。每一部分计为一颗星。让我们看看我们将收集多少颗星。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/969dc98a75a9b9c29301302ffe287c7b.png
我在 2024 年编程挑战赛中的当前进度(作者提供的图片)
第 1 天 – 第一部分
在第 1 天的谜题中,我们被给出了两个列表(左和右)。
在第一部分,我们被要求找出左列表中最小数和右列表中最小数之间的差值,对第二小的数、第三小的数等等也做同样的操作。最终答案是所有这些差值的总和。
它并没有直接询问差值,而是说“两个数字之间的距离”,所以我们需要找到差值的绝对值(即(2-4)和(4-2)是相同的)。
下面的插图展示了 3 个项目列表的解决方案:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/1dd5d0db1c2787c77310039f5f75bc8a.png
(作者提供的图片)
谜题的输入对每个用户都不同。一旦你打开一个谜题,你需要点击“获取你的谜题输入”来查看你的输入。你可以从那里复制输入,或者使用 requests 库直接将其获取到脚本中。
你可以使用下面的get_puzzle_input函数,但你需要获取自己的会话 cookie 才能检索谜题输入。
注意:最好将你的会话 cookie 保存为环境变量,并从那里获取它(例如,os.getenv(SESSION_COOKIE))。
importrequests session_cookie="your session cookie"# or session_cookie = os.getenv(SESSION_COOKIE)defget_puzzle_input(day,session_cookie,year=2024):url=f"https://adventofcode.com/{year}/day/{day}/input"cookies={"session":session_cookie}response=requests.get(url,cookies=cookies)ifresponse.status_code==200:returnresponse.textelse:returnNonepuzzle_input=get_puzzle_input(1,session_cookie)如何获取会话 cookie
一旦你打开输入页面,右键点击并选择“检查”。然后切换到“网络”标签并按“command+R”(在 Windows 上为 ctrl+R)。切换到“头部”标签并向下滚动到 cookie。你会在那里看到会话 cookie。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/844f45e25f4f3a0cbf919d5bc9be1410.png
如何获取会话 cookie(图片由作者提供)
我们现在有了拼图输入。输入如下所示,因此获取请求的输出不是两个分开的列表,格式整洁。我们需要进行一些数据处理。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/2f5b5fe7f674cb53e629b1b5e16ae087.png
拼图 1 输入的前 6 行(图片由作者提供)
puzzle_input=get_puzzle_input(1,session_cookie)print(puzzle_input)80784477318168236089222894103879525174816215670590...拼图输入是一个单独的字符串,项目之间有空间和换行符。我们可以通过换行符(“n”)拆分字符串以获取行列表。然后,我们可以通过空格字符拆分每一行。第一个项目属于左列表,最后一个项目属于右列表。
为了同时对此列表中的所有项目执行此操作,我们将使用一个列表推导。它比逐个遍历列表中每个项目的 for 循环更高效。
lines=puzzle_input.split("n")[:-1]# exclude the last item since it's just a new lineleft_list=[int(line.split(" ")[0])forlineinlines]right_list=[int(line.split(" ")[-1])forlineinlines]# print the first 5 itemsprint(left_list[:5])[80784,81682,22289,79525,62156]print(right_list[:5])[47731,36089,41038,17481,70590]下一个操作是对两个列表进行升序或降序排序。然后,我们可以找到第一个项目、第二个项目等之间的差异。在将差异相加之前,确保取差异的绝对值。最后的操作将是将这些差异相加。
我将把这些列表转换为 numpy 数组,然后进行排序、减法和求和。
# convert lists to numpy arrays and sortleft_arr=np.sort(np.array(left_list))right_arr=np.sort(np.array(right_list))# find the absolute value of element-wise differences and take the sumsum_of_differences=np.abs(left_arr-right_arr).sum()第 1 天 – 第二部分
在第二部分,我们被要求根据以下标准计算左右列表之间的相似度得分:
遍历左列表中的每个项目,并找出它在右列表中出现的次数。
然后将这个数乘以出现的次数以找到每个项目的相似度得分。
将所有相似度得分相加以获得总相似度得分。
下面的图示演示了这些计算:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/2d68e08d77c9386e570f4554f34d1672.png
(图片由作者提供)
我们可以通过使用列表推导和 Python 列表的count方法来解决第二部分,该方法返回一个项目出现的次数。
# list of similarity scoressimilarity_scores=[item*right_list.count(item)foriteminleft_list]# total similarity scoresum(similarity_scores)列表推导中的item是左列表中的项目,而right_list.count(item)是这个项目在右列表中出现的次数。将这两个数相乘给出该项目的相似度得分。然后,我们取所有项目的相似度得分的总和。
第 1 天已完成。敬请期待第 2 天 🙂