ARTS 1108: 快慢指针找中点、数据库也是全局变量的仓库与漏洞发现提速后的修复压力

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

Algorithm

这周写一道关于链表的简单难度的题目 https://leetcode.cn/problems/middle-of-the-linked-list/description/

image-20261108173648059

咱们这里用到两种不同的办法进行遍历:

  • 先拿到这个 Node 的 length 的长度,之后根据这个长度进行循环
  • 使用两个指针,使用快慢指针进行解决

第一种办法:

▼
java
复制代码
public class Solution { public ListNode middleNode(ListNode head) { int length = 0; // 这里需要存储这个 cur ListNode cur = head; while (cur != null) { length++; cur = cur.next; } for (int i = 0; i < length / 2; i++) { head = head.next; } return head; } } class ListNode { int val; ListNode next; ListNode(int val) { this.val = val; } ListNode() { } }

第二种办法:

原理:这个原理是因为慢指针永远都走快指针的一般,这样快指针走完之后,慢指针的位置刚好就是我们需要的位置

注意事项:

  • 注意快指针的边界条件,当 fast == null 或者 fast.next == null 的时候都说明一点,就是到对应的位置了,具体可以看下面的图片
  • 情况是 fast.next == null

image-20261108201358711

  • 情况是 fast == null

image-20261108201418302

  • 这个 while 循环的时候需要注意是判断 fast 如果判断 slow 会出现 NPE
▼
java
复制代码
public class Solution { public ListNode middleNode(ListNode head) { // 快慢指针解决这个问题 ListNode slow = head; ListNode fast = head; while (fast != null) { if (fast.next != null) { fast = fast.next.next; } else { return slow; } slow = slow.next; } return slow; } }

Review

文章:A database is a store for global variables

Sean Goedecke 从一个矛盾出发:编程时经常被告诫少用全局变量,但数据库同样保存着程序各处可以共享和修改的状态。为什么前者被视为设计问题,后者却很常见?

作者认为,两者都有隐式传递数据和耦合不同模块的问题。一处代码修改记录,另一处代码依赖它的值,双方即使没有直接调用,也会相互影响。事务可以保证一组修改的原子性,却不能消除这种依赖。

作者更认可的解释是:数据库访问通常更显式,而且使用方式有约定。查询调用让共享状态的读写更容易被发现,团队也通常只用数据库保存特定用途的数据。但这些优势依赖使用方式,隐藏查询的抽象也可能削弱它们。

因此,作者没有建议大量使用全局变量,而是提醒读者:设计经验需要能解释原因,不能仅凭「最佳实践」判断方案好坏。

沿着这个观点审视代码,可以把注意力放到共享状态的读写责任上:哪些模块有权修改,读取方依赖什么条件,修改后会影响哪些流程?这些问题比变量存在哪里更能帮助判断耦合是否可控。

进一步说,数据库约束和业务规则也需要区分。字段类型、非空约束能够限制数据形态,但业务状态是否允许转换、多个写入方是否遵守相同规则,仍然需要在应用设计中明确。审查时可以沿着一条状态变化查找全部读写位置,检查依赖是否清楚,再决定是否需要收拢写入入口或补充约束。

Tips

让 AI 写代码时,除了说清楚要什么功能,还要讲明实际规模、任务边界和维护成本,不然它会替还没出现的需求写代码。

膨胀来源

1、按想象的规模做优化。还没遇到瓶颈,就先加了缓存、批处理和复杂调度。

2、一个设计选择带出一串代码。换个方案可能直接去掉一整组依赖,这比逐行删代码收益大。

3、状态和抽象越分越细。只有对应不同业务行为的区别才值得保留。

4、降级越叠越多。最后失败处理比正常流程还复杂。要不要降级,看业务能不能接受失败。

5、辅助代码没有依据。指标、配置项、内部校验和测试接口,每一项都要说得出用途。

下任务时的约束

1、给出实际规模和代码预算,比如数据量、并发量、性能要求和大致代码量。

2、先审方案再写代码。让 AI 先说明核心流程、需要哪些组件、预计多少代码、哪些暂时不做。

3、先找现有能力。项目里或标准库已经有的,就直接复用。

4、新增复杂度要有理由。每加一个状态、抽象层、配置项、降级或日志,都要对应真实需求。

5、按风险安排测试。重点覆盖核心结果、重要边界和失败处理,不要每个类都配一个测试。

Share

文章:The PHP2Shell Vulnerability Heralds Cybersecurity Hell

这篇文章借 PHP2Shell 讨论了一个变化:AI 正在加快对旧软件的安全研究,过去积累的技术债可能更快暴露出来,而维护者未必有同样充足的资源应对。

1、漏洞研究能力的提升,会改变旧问题的风险判断。

报道介绍,研究人员借助 AI,把已知的内存处理问题推进到了可执行任意代码的利用路径。这里仍然需要专家的安全知识和判断,不能据此认为 AI 已经能独立完成整个过程。

由此可以推想,「暂时没有发现利用方式」不能成为长期搁置问题的充分理由。评估历史缺陷时,需要随研究工具和攻击能力的变化重新判断风险。

2、发现问题和安全修复问题,承担的工作不同。

文章引用研究者的观点:修复既要封住攻击路径,也要保证原有功能不被破坏。这种不对称意味着,漏洞发现提速之后,修复和验证可能承受更大压力。

PHP 基金会的事件说明进一步指出,修复曾受兼容性、性能、扩展生态和决策机制的制约。工具也带来了更多无效、重复或无法复现的报告,需要维护者逐一处理。提高安全能力,需要同时考虑报告质量、修复能力和发布协调。

3、防御端也需要工具和持续投入。

报道讨论了为开源维护者提供资金、模型资源,以及用形式化验证辅助检查补丁的方向。这些是改善修复效率的可能路径,不能直接理解为漏洞修复已经可以全面自动化。

对依赖开源软件的组织而言,可以据此检查自身的维护安排:是否清楚关键依赖由谁负责,是否有安全更新和回归验证的流程,是否能持续支持所依赖的项目。引入扫描工具之后,还需要有人判断报告、推进修复,并把补丁部署到实际系统中。

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
leikooo
作者分享
MySQL 如何让并发看起来像串行?
6
让 AI 改代码,有时候会遇到一个问题:需求完成了,但多了几个 if;再补一个需求,又加了几个特殊判断。改的时候都说得通,回头看,代码已经绕得有点看不懂了😭。 最近发现 Cursor 的 cursor-team-kit 里有个 skill,叫 thermo-nuclear-code-quality-review,用下来效果挺不错。名字挺狠,可以翻译成「热核级代码质量审查」。它会让 AI 更严格地检查代码,看看哪些地方越改越乱,有没有更简单的写法。 平时让 AI 做 code review,我们往往更关心有没有 bug,边界情况有没有漏掉。这个 skill 会把后续维护也作为审查重点:功能没问题,但下次加需求是不是又得四处补判断?别人接手时,能不能看懂这段代码?如果能在不改变功能的前提下减少分支、去掉多余的封装,它就会要求把这些地方改得更简单。 它查得比较细:有没有到处补条件判断,有没有封装了一层却什么也没简化,业务代码是不是放错了地方。如果这次修改让一个文件从不到 1000 行涨到超过 1000 行,也会要求检查是否该拆分,有充分理由才保留。 安装可以直接交给 AI。在支持安装 skill 的编程工具里,把 GitHub 地址发过去就行: > 帮我安装这个 skill:https://github.com/cursor/plugins/blob/main/cursor-team-kit/skills/thermo-nuclear-code-quality-review/SKILL.md 装好之后,写完一轮代码,让它用这个 skill 检查一下。这时最好说清楚审查范围,比如: > 用 thermo-nuclear-code-quality-review 检查当前分支相对 main 的改动,保存到 docs 目录下面的文件中 最后,如果条件允许,改完还可以换另一家的模型复查一次,把修改后的代码和需求一起给它,看看有没有遗漏,或者为了简化代码改掉了原本的行为。多次校验一下,这样上线才更稳定一些。
8
ARTS 1101: 最长回文串与子序列匹配、一次 URL 请求的来回之旅与如何验证 AI 的交付
6
IP 数据库体积缩小 31%,关键竟然是合并重复子树
4
提到用 Rust 重写项目,很多人的第一反应往往是性能提升。以 Bun 为例,它最初主要采用 Zig 开发,后来在 2026 年发布的 v1.4 版本中将核心代码迁移到了 Rust。用 Rust 重写,性能、安全性往往是大家想要的,但是有没有想过用 Rust 重写还能发现 bug 呢? pgrust 这个项就是,他用 Rust 重新实现 PostgreSQL,保持通信协议和 SQL 方言兼容。为了确认新系统的行为和原版一致,开发者需要对着 PostgreSQL 的实际返回逐个比对。结果查着查着,有些异常不是新代码的锅,PostgreSQL 自己就是这样的。pgrust 开发者 Michael Malis 把其中几个报告给了 PostgreSQL 社区。 大概的问题: 1)SP-GiST 空间索引里有个函数判断点的方位,代码认为上、下、同一水平线三种情况已经穷尽了,末尾放了句「impossible case」兜底。结果在特定浮点边界附近,三种判断同时不成立,程序真走进了这个「不可能」的分支 2)日期格式缓存复用时,一个解析模式的标记没重置,导致同一条 JSONPath 查询在同一个会话里,换个执行顺序结果就不一样。 3)pgcrypto 的 crypt() 在某些输入下截断了多字节字符,返回的文本编码不合法。能存进去,但 pg_dump 导出时就炸了。 一个用 Rust 重写的新项目,测着测着,把运行了几十年的 PostgreSQL 里埋着的东西翻了出来。Rust 重写的价值,不一定只在跑得更快、更安全这一件事上。为了做到真正的兼容,开发者得把前人没怎么碰过的边界全走一遍,这个过程本身就在帮原版排雷。
4
下载 APP