ARTS 1025:唯一字符與同構字符串、省詞可能增加閲讀負擔,以及重新估算軟件實現成本
ARTS 1025: 唯一字符与同构字符串、省词可能增加阅读负担与重新估算软件的实现成本
ARTS 1025 分享兩道 LeetCode 題目的解法,並討論 AI 生成語言的精簡表達如何增加讀者的理解負擔,以及 AI 編程工具如何改變軟件項目的實現成本。文章指出,省略連接詞、名詞堆疊和長距離依存等表達,可能讓讀者自行補足關係;開發者則可重新評估以往因成本過高而放棄的項目,但仍須驗證實現是否符合預期。
简介: 每周完成一个 ARTS: 至少做一个 leetcode 的算法题、阅读并点评至少一篇英文技术文章、学习至少一个技术技巧、分享一篇有观点和思考的技术文章。(也就是 Algorithm、Review、Tips、Share 简称 ARTS)## Algorithm这周因为都是简单难度的,所以来写两道算法题目:1)第一道:LeetCode [387. 字符串中的第一个唯一字符](https
每周完成一个 ARTS: 至少做一个 leetcode 的算法题、阅读并点评至少一篇英文技术文章、学习至少一个技术技巧、分享一篇有观点和思考的技术文章。(也就是 Algorithm、Review、Tips、Share 简称 ARTS)
Algorithm
这周因为都是简单难度的,所以来写两道算法题目:
1)第一道:LeetCode 387. 字符串中的第一个唯一字符

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

有几点需要注意:
- 错误把“出现次数相同”当成了“同构”。不能只是单纯的判断,字母出现的数量进行对比。
- 只检查了映射的一致性,漏掉了映射的唯一性。如果一个 a -> b a -> a 这样也不是同构的,所以这里我们使用 Set 进行判断。
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,即使这个项目最终没有成功,这些发现也能帮助已有软件改进。
不过,作者并没有得出「软件开发已经解决了」的结论。他发现,模型能实现的东西越来越多,但在缺少人工指导时,能够有效验证的范围没有同步跟上。尝试更复杂的项目之后,人仍然需要判断实现是否符合预期。
來源:阿里雲開發者社區 AI · developer.aliyun.com