ARTS 1025: 唯一字符与同构字符串、省词可能增加阅读负担与重新估算软件的实现成本

每周完成一个 ARTS: 至少做一个 leetcode 的算法题、阅读并点评至少一篇英文技术文章、学习至少一个技术技巧、分享一篇有观点和思考的技术文章。(也就是 Algorithm、Review、Tips、Share 简称 ARTS)

Algorithm

这周因为都是简单难度的,所以来写两道算法题目:

1)第一道:LeetCode 387. 字符串中的第一个唯一字符

image-20261025153942993

这道题目住要的办法就是,先用 Map 拿到每一个 Charecter 出现的次数,然后根据 map 记录的内容进行返回 index。这有一点需要注意:HashMap 不保证元素的遍历顺序与插入顺序一致。如果需要按照插入顺序遍历元素,可以使用 LinkedHashMap

▼
java
复制代码
class Solution { public int firstUniqChar(String s) { Map<Character, Integer> map = new HashMap<>(); char[] chars = s.toCharArray(); for (char c : chars) { map.merge(c, 1, Integer::sum); } for (int i = 0; i < chars.length; i++) { if (map.getOrDefault(chars[i], null) == null || map.get(chars[i]) > 1) { continue; } return i; } return -1; } }

2)第二道:LeetCode 205. 同构字符串

image-20261025154541343

有几点需要注意:

  • 错误把“出现次数相同”当成了“同构”。不能只是单纯的判断,字母出现的数量进行对比。
  • 只检查了映射的一致性,漏掉了映射的唯一性。如果一个 a -> b a -> a 这样也不是同构的,所以这里我们使用 Set 进行判断。
▼
java
复制代码
class Solution { public boolean isIsomorphic(String s, String t) { if (s.length() != t.length()) { return false; } Map<Character, Character> charMap = new HashMap<>(); Set<Character> usedTargets = new HashSet<>(); for (int i = 0; i < s.length(); i++) { char sC = s.charAt(i); char tC = t.charAt(i); Character mapped = charMap.get(sC); if (mapped == null) { // tC 已经被其他字符使用,不能重复映射 if (!usedTargets.add(tC)) { return false; } charMap.put(sC, tC); } else if (mapped != tC) { return false; } } return true; } }

Review

论文:Why is AI-generated language so hard to understand?

作者提出一个假说:训练中压缩信息的压力,可能让模型更偏爱紧凑、省词的表达。这些表达在语法上说得通,却可能让读者花更多精力判断词义、记住前文、补出句子里的关系。

1、阅读时,读者需要不断预测后文、记住前文。

看到一个词时,读者已经在结合上下文判断它的意思。论文引用的心理语言学研究发现,越难预测的词,通常需要越长的阅读时间。词语搭配不常见,读者就更难顺着前文理解下去。

记忆也会影响阅读。如果主语和对应的动词隔得很远,读到动词时,就得找回前面的主语,再把两者联系起来。相互关联的词之间隔了多远,称为「依存距离」。一句话里需要暂时记住的信息越多,理解起来就越费力。所以,判断句子是否好读,不能只看字数,还要看读到哪里才能确定它在说什么。

2、论文检查了六类可能增加阅读负担的表达。

下面结合例子说明,其中的中文例子是为帮助理解补充的。

罕见的词语搭配,可能让人每个词都认识,连起来却不熟悉。例如,论文开头的 reader-patience budget,字面上是「读者耐心预算」。读者需要先理解这里把耐心比作一种会被消耗的预算,才能明白整个词组。写成「读者愿意花多少耐心读下去」,含义就直接一些。

长距离依存,会让读者更久地记住还没读完整的内容。例如,「负责处理缓存失效后大量请求同时访问数据库问题的服务需要重启」,读到「服务」时,才知道前面一大段都在修饰它,接着还得把它和「需要重启」联系起来。可以拆成:「这个服务负责处理缓存失效后大量请求同时访问数据库的问题。现在需要重启它。」先交代服务的用途,再说要做什么,读者就不用把整串修饰语一直记到句尾。

宾语关系从句中的省略,可能让句子少一些结构提示。例如,The patch the engineer reviewed failed. 的意思是「工程师审查过的补丁失败了」。句子的主干是 The patch failed.,中间的从句说明补丁被谁审查过,the patch 是 reviewed 的宾语。写成 The patch that the engineer reviewed failed.,多出的 that 标出了从句的开始。省去它也符合语法,但读者需要更依赖后文来判断结构。相关研究发现,人类会根据后续内容是否容易预测,决定要不要省略这类词。

名词堆叠,会省去概念之间的关系。例如,「缓存失效回源并发保护策略」把几个概念连在一起,读者需要自己判断哪些是条件、动作和目的。可以展开成:「缓存失效后,请求会访问数据库。为避免大量请求同时回源,可以限制同时回源的请求数。」多出来的文字,把原来需要读者推断的关系写了出来。

名词转动词,也能把原本需要几个词说明的动作缩短。例如,把表示日历的 calendar 当作动词,就可以表达「把某件事记入日历」。这类用法依赖说话者和读者对情境的共同理解。如果上下文不够充分,读者就得先猜这个词在当前句子里指什么动作。

还有一类是让没有生命的事物去做通常由人或动物完成的动作。例如,论文中的 this asymmetry bites,需要把「咬」理解成「造成问题」。在技术说明中,仅写「这个不对称性会反咬一口」,读者还得继续追问它具体影响什么。直接说明它会导致什么错误,更方便判断影响范围。名词转动词和拟人表达都可以正常使用,是否难读,还取决于读者对这种用法的熟悉程度,以及上下文是否充分。

3、训练目标可能强化了这些表达偏好。

作者推测,数学、代码等后训练任务可以奖励答案正确,却未必奖励读者是否容易理解。再加上上下文长度和 token 成本的限制,模型可能逐渐偏向用更少的词表达更多信息。

放到文档里看,省掉连接词、把动作写成名词、把背景放进一长串修饰语,确实可能缩短输出。但条件和因果关系不会因此消失,它们只是需要读者自己还原。对模型来说省下了词,对读者来说却可能多了一步推断。

人类的表达会随语境调整:容易预测的内容可以省略,新信息多的地方则需要更多提示。前面是否保留 that 的例子,就说明了这种取舍。省略是否合适,要看读者能不能顺着上下文理解下去。

对我们的启发就是,在写技术笔记时,可以留意那些需要读者自己补全的地方:主语是否明确,修饰语能否拆开,几个名词之间是什么关系,隐喻具体指什么行为和结果。让 AI 润色时,也可以要求保留条件和因果关系,再根据读者已有的知识,决定哪些内容可以省略。

Tips

1、macOS 使用 FineTune 可以管理不同软件得声音,非常实用。开源地址: https://github.com/ronitsingh10/FineTune

2、epub 阅读器,可以使用这个开源项目:https://github.com/readest/readest

3、继续学习 Rust 相关的内容,学到 Lifetimes 了,继续冲

Share

文章:We should be more ambitious with the software we build

Dan Luu 提出了一个值得重新考虑的问题:有了 AI 编程工具之后,哪些过去因为成本太高而放弃的事情,现在已经值得做了?他更倾向于说「可以更有野心」,因为工具能力的变化,让开发者有机会尝试以前做不起的软件。

1、判断一个项目值不值得做,需要重新估算实现成本。

过去,嫌编译慢就自己改编译器,嫌搜索慢就自己写正则引擎,通常意味着投入大量时间,还可能耽误原本要完成的工作。因此,优先使用现成工具、避免重复造轮子,是很合理的选择。

但 Dan Luu 发现,有些判断已经需要更新。他针对自己的使用场景,尝试了正则引擎、ripgrep 分支和 Rust 编译加速等项目,投入的个人时间比过去少了很多。开发者可能还沿用着没有编程 Agent 时的成本估计,连试一下都觉得不划算。

这里也要保留作者给出的范围:这些工具主要达到了「自己能用」的程度,做成可靠的公共项目仍然需要更多工作,文中也没有提供完整、严谨的性能评测。这些经历更适合用来说明尝试的成本发生了变化,具体收益还要在实际场景中测量。

2、值得尝试的软件,也可以只解决一个很小的需求。

文章中有个例子很有意思:Dan Luu 一直想玩一款还原小说中太空战斗方式的游戏,但这种玩法很小众。过去,花十几个小时开发,再玩一两个小时,并不划算;当他只需要花几分钟安排 Agent 实现时,这件事就值得做了。

这种变化也适用于日常工具。比如,一个脚本只能省下每次几分钟的手动操作,过去因为开发和维护太麻烦,一直没有人写。现在可以先做一个范围很小的版本,用几次看看是否方便,再决定要不要继续完善。软件只供几个人使用,也可能有足够的价值。

3、项目能做得更大,验证也得跟得上。

Dan Luu 用 pgrust 数据库项目说明,有质量问题的 AI 项目很多,但认真测试的项目仍然能产生价值。按他的介绍,pgrust 的测试过程甚至找出了 PostgreSQL 本身的 Bug,即使这个项目最终没有成功,这些发现也能帮助已有软件改进。

不过,作者并没有得出「软件开发已经解决了」的结论。他发现,模型能实现的东西越来越多,但在缺少人工指导时,能够有效验证的范围没有同步跟上。尝试更复杂的项目之后,人仍然需要判断实现是否符合预期。

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
leikooo
作者分享
🎉 1024 程序员节快乐! 祝编程导航里的每一位程序员:offer 多多,薪资翻倍,面试顺利,早日拿下心仪 offer!💻
17
AST:从 Java 代码理解抽象语法树
5
原来维基百科还有专门研究「AI 味」的页面 今天偶然发现一个挺有意思的维基百科页面:https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing,专门整理 AI 写作的典型特征。 里面总结了很多我们平时经常看到的 AI 味,比如喜欢用“值得注意的是”“在当今快速发展的时代”“综上所述”,还有过度使用排比、加粗、列表,以及一些看起来很有道理,实际上没什么信息量的表达。 感觉以后可以定期翻翻这个 wiki,尤其是经常使用 AI 辅助写作的人,应该能从中发现不少所谓的 AI 味。 链接: https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing
5
ARTS 1018: 字符计数判断异位词、局部做对仍会增加维护负担与用 AI 也要理解自己在做什么
4
AI 越强,被它拒绝的代价就越大 我有时候会想:AI 越来越厉害之后,有些事情,会不会反而越来越难做? 这个想法看起来有点矛盾。AI 明明在降低门槛,让不会写代码的人做出软件,让不会画画的人生成图片,让一个人完成过去需要整支团队才能完成的工作。但今天用 Codex 的时候,AI 拒绝帮我编写 SQL 注入的请求体,而那还是我有源码、在本地跑测试的情况。那么,往后是否只会更难? 我们假设某一天,AI 说:「这个请求违规,我不能帮助你。」到那个时候,你还有多少能力,能绕过它,把事情做完? 这里的「违规」需要打个引号。平台的规则、模型的判断、法律的要求,以及一件事实际有没有造成伤害,彼此之间并不总是画得上等号。一个请求可能确实危险,也可能只是缺少上下文被误判,或者恰好落在某家公司的限制范围里。 无论是哪种情况,随着我们越来越依赖 AI,这句拒绝都可能变得越来越贵。 今天,一个程序员让 AI 帮忙写代码,AI 拒绝了,他大概率还有别的办法:查文档、找开源项目、问同行,或者自己写。麻烦一点,慢一点,但路还在。 可如果十年之后,大部分程序都由 AI 完成,情况就不一样了。 很多人从接触编程的第一天起,就习惯了描述需求、等待生成、运行结果、继续迭代。他们能做出相当复杂的产品,却未必经历过独立处理底层问题的训练。平时,这种能力结构完全够用,效率甚至更高。只有 AI 拒绝的时候,他们才会发现:平常被省掉的那段学习过程,恰好是此刻最需要的东西。 到那时,一次拒绝的成本,可能就从「今晚多花两个小时」,变成「先花半年学会这门技术」。 拿 SQL 注入举个稍显极端的例子:往后,连真正理解这类攻击如何发生、能够独立构造测试的人,会不会也越来越少? 这里也包括那些有正当需求的人。一个开发者想检查自己的旧系统,一个经过授权的安全研究员想复现漏洞,假如 AI 识别到危险模式就拒绝,而使用者又只熟悉「让 AI 帮我检查」,这项原本可以独立完成的工作,就这样卡住了。 但是安全专家不会因此消失,但这类技能可能越来越集中在少数人手里。你仍然可以找专家,只是要付出更多的钱、更多的时间,以及更高的沟通成本。 类似的困境,未必只发生在网络安全领域。 你想从一个停止维护的软件里取回自己的数据,需要解析它的旧文件格式。AI 判断这涉及规避保护措施,拒绝继续。你拥有这些数据,却没有能力把它们读出来。 你买了一台设备,厂商停止提供服务。你想修改程序让它继续运转,过程中需要处理某种访问限制。AI 不愿协助,而你所掌握的维修方式,早已只剩下「把报错发给 AI」。 你想给常用的网站写一个辅助工具,减少重复操作。平台将此归入自动化限制,AI 也据此拒绝。过去会写脚本的人可以自己判断、自己处理;未来的使用者,可能连从哪里开始都不知道。 这些例子有一个共同点:当工具同时承担了「执行工作」和「传授知识」的角色,它的拒绝就不只是挡住了一次任务,也挡住了获得这种能力的机会。 更麻烦的是,这种依赖往往是我们主动选择的,而且每一步都很合理。 既然 AI 几秒钟就能做好,为什么还要花几个月学习?既然公司可以采购成熟的 AI 服务,为什么还要养一支负责基础工作的团队?既然市场上已经很少有人手写这些东西,学校为什么还要花大量时间教? 对个人、公司和学校来说,这些选择都有现实依据。但叠加起来,整个社会保留的独立能力就可能越来越少。等到某项能力突然受到限制,我们才发现,备用方案早已在追求效率的过程中被一点点削掉了。 所以,「AI 越强,做事越便宜」可能只描述了未来的一半。 另一半是:被允许的事情越来越便宜,被拒绝的事情依然需要人工完成,却要面对更少的人才、更高的报价,以及越来越难获得的知识。两边的成本差距,会越拉越大。 有人会说,可以换一个模型,或者用本地模型。这确实是重要的选项。只要工具之间还有充分竞争,开放模型还足够可用,限制就未必能形成真正的门槛。 但备用方案也需要维护。它需要硬件、知识、软件生态,以及一群仍然理解这些系统的人。如果大多数人已经习惯了最方便的商业服务,那么「理论上还有别的办法」和「普通人实际用得起、用得明白」,之间仍然可能隔着很远。 我担心的,正是这段距离。 我不指望 AI 对任何请求都照单全收。对明显会伤害他人的行为设置限制,有充分的理由。但我们也需要关心:限制由谁定义,误判有没有申诉渠道,用户能不能换工具,以及脱离这个工具之后,还剩下多少独立行动的能力。 保留这些能力,平时看起来甚至有点低效,明明可以自动生成,还要理解原理;明明可以一键完成,还要知道手动怎么做。 但这些看似多余的知识,会在工具拒绝、失效、涨价或改变规则的那一刻,成为真正的选择权。 AI 越强,我们可能越需要留意它说「不」的那一刻。 因为那句话的分量,最终取决于:它拒绝之后,我们还能做什么。
10
下载 APP