如何为 Code 4 的出现编写排序算法
从现在开始,我们要努力学习啦!今天我给大家带来《如何为 Code 4 的出现编写排序算法》,感兴趣的朋友请继续看下去吧!下文中的内容我们主要会涉及到等等知识点,如果在阅读本文过程中有遇到不清楚的地方,欢迎留言呀!我们一起讨论,一起学习!
在上一篇文章中,我简单提到我将参加今年的“代码降临”活动。巧合的是,在其中一个谜题中,特别是在第 5 天发布的谜题中,涉及修复列表中页面的顺序。这是在我发布关于实现排序算法的文章后不久,所以我认为我应该写一下它。
描绘某种排序算法的可爱图像
对于那些没有听说过“advent of code”的人来说,这是由 eric wastl 主办的年度活动。每年,它都会讲述一个以节日为背景的故事,今年的故事是关于寻找首席历史学家,他可能是每次大型圣诞雪橇发射中的重要人物。该挑战将于每年12月1日持续至25日。每天,剧情都会进展,并且包含一个编程谜题(并且带有输入)。
在故事叙述中,谜题通常被明确定义,并包含测试用例。每个谜题都分为两部分,第二部分只有在提交第一个答案后才会出现。
参与者可以用任何语言实现任何算法,甚至完全跳过编程,只要派生的答案匹配即可。今年我尝试用 python 编写解决方案,9 天后,我觉得我在整个过程中学到了很多东西。
第五天,故事要求帮忙印刷安全手册。输入包含页面规则和精灵尝试打印的页面列表。
47|53 97|13 97|61 97|47 75|29 61|13 75|53 29|13 97|29 53|29 61|53 97|53 61|29 47|13 75|47 97|75 47|61 75|61 47|29 75|13 53|13 75,47,61,53,29 97,61,53,29,13 75,29,13 75,97,47,61,53 61,13,29 97,13,75,29,47
让我们从解析输入开始:
def parse( input: str, ) -> tuple[tuple[tuple[int, int], ...], tuple[tuple[int, ...], ...]]: def inner( current, incoming ) -> tuple[tuple[tuple[int, int], ...], tuple[tuple[int, ...], ...]]: rules, pages = current if "|" in incoming: return rules + ( tuple(int(item) for item in incoming.strip().split("|")), ), pages else: return rules, pages + ( tuple(int(item) for item in incoming.strip().split(",")), ) return reduce( inner, filter(lambda line: line.strip(), input.strip().splitlines()), ((), ()) )
该函数接收名为 input 的字符串形式的输入,使用 .splitlines() 将其分成几行,然后发送到内部函数以生成两个元组,一个用于页面规则,另一个用于页面序列。该代码通过分隔符 | 区分两种类型的定义。表示页面规则, , 表示页面。
在拼图的第一部分,故事要求检查页面是否按顺序排列。让我们从实现一个完成这项工作的函数开始:
def check_pair(rules: tuple[tuple[int, int], ...], alpha: int, beta: int) -> bool: return (beta, alpha) not in rules
然后另一个函数发送所有页面组合(combinations((1,2,3), 2) 返回 1,2, 1,3 和 2,3):
from itertools import combinations def check_pages(rules: tuple[tuple[int, int], ...], pages: tuple[int, ...]) -> bool: return all( check_pair(rules, alpha, beta) for alpha, beta in combinations(pages, 2) )
我将这两个函数分成单独的函数的主要原因是我想让每个部分尽可能小。根据我的经验,保持事物足够小不仅可以使其可测试,通常还有助于调试最终输入(通常很大)。
很多时候,第 2 部分会让人感到惊讶,并且经常会发现它要求对第 1 部分的代码设计进行修订。这可能是您已实现的内容的一个小变化,或者需要不同的功能不同目标的调用顺序等。我确实保持在工作中编写短函数的习惯(作为注释的替代)。
像这样的小函数只有名字好才有效,所以你需要注意命名。这需要练习,但是一旦你熟练了,这种方法就可以使代码变得非常自我记录。较大规模的函数读起来就像一个故事,读者可以根据需要选择深入了解哪些函数以了解更多细节。
引用自 martin fowler 撰写的题为 function length 的文章
回到谜题。
最后,谜题要求计算所有页面排序正确的情况下中间页码的总和。
def get_middle(pages: tuple[int, ...]) -> int: return pages[len(pages) // 2] def part1(input: str) -> int: rules, pages_list = parse(input) return sum( get_middle(pages) for pages in pages_list if check_pages(rules, pages) )
非常简单,如果你已经完成了所有正确的事情,那么它只是一个列表理解(因为 python 开发人员更喜欢这个而不是映射/过滤器)。
接下来是排序算法:
继续第 1 部分,第二部分想要中间页的总和,但适用于页面排序不正确的情况。该指令还要求在检索中间页码之前修复顺序。
虽然我的同行在没有成熟的排序算法的情况下设法解决了这个问题,但我决定按照前面描述的难题(在解释页面规则的部分中)的确切方式来完成它。我已经完成了比较部分(check_pair),现在我需要一个可以移动元素的函数。
def move(items: tuple[int, ...], current: int, incoming: int) -> tuple[int, ...]: assert incoming > current return ( *items[:current], items[incoming], *tuple( item for idx, item in enumerate(items) if (idx >= current) and not (idx == incoming) ), )
假设我有 1,2,3,4,5,该函数将传入的数字移动到当前数字的前面。假设current = 2,传入= 4,那么我将得到1,4,2,3,5作为回报(假设我们是按照递增的数值排列)。
我向朋友解释算法的失败尝试
下一步是将我手写草稿中显示的算法转化为实际代码。
def sort_pages( rules: tuple[tuple[int, int], ...], pages: tuple[int, ...], pointer: int = 0, subpointer: int = 0, ) -> tuple[int, ...]: return ( sort_pages( rules, *next( ( (move(pages, pointer, incoming), pointer, pointer + 2) for incoming in range(subpointer, len(pages)) if check_pair(rules, pages[pointer], pages[incoming]) is false ), (pages, pointer + 1, pointer + 2), ), ) if pointer < (len(pages) - 1) else pages )
是的,不幸的是它是递归的。我应该发布第一个版本,这可能更容易阅读:
def sort_pages( rules: tuple[tuple[int, int], ...], pages: tuple[int, ...] ) -> tuple[int, ...]: result, pointer = pages, 0 while true: if pointer == (len(pages) - 1): break changed = false for incoming in range(pointer + 1, len(pages)): if check_pair(rules, result[pointer], result[incoming]) is false: result = move(result, pointer, incoming) changed = true break pointer = 0 if changed else pointer + 1 return result
两者本质相同,只是最终的功能版本略有优化。参考草稿截图,我有两个指针,黄色下划线在代码中名为指针,传入蓝色下划线。
算法的工作原理如下:
- 首先将指针设置为第一个元素。
- 最初传入的总是它旁边的元素。
- 传入的指针将一次遍历一个元素,如果违反规则,会将值移至当前元素之前。
- 一旦发生这种情况,传入指针将重置,并移回当前的下一个。
- 当前指针没有改变位置,但它现在指向上一步中插入的新元素。
如果传入指针设法逐步遍历列表的其余部分而没有引入任何更改,则我们将当前指针前进(并且传入指针重新初始化到它旁边的位置),并再次重复该过程。
算法完成对最后 2 个元素的比较后,该过程结束,然后返回排序后的页面作为结果。然后,我们可以继续组装第 2 部分中的所有内容:
def part2(input: str) -> int: rules, pages_list = parse(input) return sum( get_middle(sort_pages(rules, pages)) for pages in pages_list if check_pages(rules, pages) is False )
两个部分的代码相似。它只是对第 1 部分进行了轻微修改,只是过滤器子句中的一些变化,并且 get_middle 接收的是排序列表。本质上, if 就好像我正在以函数形式的构建块以稍微不同的组合来组装答案。
虽然这仍然不是一个有效的算法,因为时间复杂度接近 o(n^2)。根据windsurf中的cascade ai-companion,该算法在某些方面类似于插入排序(是的,这就是ai工具有用的时候,为算法提供解释)。
今天就这样,我很高兴算法运行良好,尽管我的生活目前一团糟(由于资金问题刚刚从一个项目中退出)。希望随着时间的推移事情会变得更好,下周我会再写。
今天带大家了解了的相关知识,希望对你有所帮助;关于文章的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~

- 上一篇
- 让你的电脑桌面焕然一新:精选清新壁纸推荐

- 下一篇
- JavaScript语法规范在哪里寻找?
-
- 文章 · python教程 | 8小时前 |
- Python能干啥?手把手教你从小白到大神的Python实战应用
- 356浏览 收藏
-
- 文章 · python教程 | 8小时前 |
- 保姆级教学!手把手教你搭建Python环境(超详细步骤)
- 329浏览 收藏
-
- 文章 · python教程 | 8小时前 |
- PythonLambda从入门到精通:手把手教你玩转匿名函数
- 330浏览 收藏
-
- 文章 · python教程 | 8小时前 |
- Python双斜杠“//”运算符啥意思?超简单一句话搞定
- 149浏览 收藏
-
- 文章 · python教程 | 8小时前 |
- Python调试实战教学:手把手教你用工具+技巧快速揪出代码bug
- 486浏览 收藏
-
- 文章 · python教程 | 9小时前 |
- Python中的float是什么?手把手教你搞定浮点数类型
- 449浏览 收藏
-
- 文章 · python教程 | 9小时前 |
- Python自动化办公:手把手教你批量处理邮件超简单!
- 255浏览 收藏
-
- 文章 · python教程 | 10小时前 |
- Python高性能计算,这些代码优化加速技巧快收藏!
- 112浏览 收藏
-
- 文章 · python教程 | 10小时前 |
- Pythonsort()vssorted():一篇文章教你搞定列表排序差异
- 223浏览 收藏
-
- 文章 · python教程 | 10小时前 | Python 线程安全 队列 queue模块 threading.Lock
- Python队列教程!手把手教你打造超简单的线程安全队列
- 444浏览 收藏
-
- 文章 · python教程 | 10小时前 |
- Python中的append怎么用?列表追加功能超详解
- 167浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- 茅茅虫AIGC检测
- 茅茅虫AIGC检测,湖南茅茅虫科技有限公司倾力打造,运用NLP技术精准识别AI生成文本,提供论文、专著等学术文本的AIGC检测服务。支持多种格式,生成可视化报告,保障您的学术诚信和内容质量。
- 88次使用
-
- 赛林匹克平台(Challympics)
- 探索赛林匹克平台Challympics,一个聚焦人工智能、算力算法、量子计算等前沿技术的赛事聚合平台。连接产学研用,助力科技创新与产业升级。
- 95次使用
-
- 笔格AIPPT
- SEO 笔格AIPPT是135编辑器推出的AI智能PPT制作平台,依托DeepSeek大模型,实现智能大纲生成、一键PPT生成、AI文字优化、图像生成等功能。免费试用,提升PPT制作效率,适用于商务演示、教育培训等多种场景。
- 98次使用
-
- 稿定PPT
- 告别PPT制作难题!稿定PPT提供海量模板、AI智能生成、在线协作,助您轻松制作专业演示文稿。职场办公、教育学习、企业服务全覆盖,降本增效,释放创意!
- 93次使用
-
- Suno苏诺中文版
- 探索Suno苏诺中文版,一款颠覆传统音乐创作的AI平台。无需专业技能,轻松创作个性化音乐。智能词曲生成、风格迁移、海量音效,释放您的音乐灵感!
- 92次使用
-
- Flask框架安装技巧:让你的开发更高效
- 2024-01-03 501浏览
-
- Django框架中的并发处理技巧
- 2024-01-22 501浏览
-
- 提升Python包下载速度的方法——正确配置pip的国内源
- 2024-01-17 501浏览
-
- Python与C++:哪个编程语言更适合初学者?
- 2024-03-25 501浏览
-
- 品牌建设技巧
- 2024-04-06 501浏览