ARTS 0830: 有效括号、LLM 在预测下一个词与真正昂贵的是逐对象 new/free

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

Algorithm

这周我们写一个关于栈相关的题目。我们来介绍一下什么是栈,并且栈可以这么实现?

1、栈(stack)是一种遵循先入后出逻辑的线性数据结构。支持的操作是 pop(出栈)、push(入栈)、peek(访问栈顶元素)

2、栈如何实现,分为两种实现方式:数组和链表,两种方式各有优缺点:

1)数组:时间效率相对不稳定,因为如果出现数组扩容的情况插入效率会下降很多;空间效率可能会浪费一些空间,因为扩容的时候会数组长度 x 2

2)链表:时间效率更稳定一些;需要存储额外的指针,占用空间相对较大

对应的简单代码实现:

1)Array实现:

▼
java
复制代码
// Array 实现栈 private final ArrayList<Integer> stack = new ArrayList<>(10); public void push(Integer i) { stack.add(i); } public Integer pop() { int index = stack.size() - 1; return stack.remove(index); } public Integer peek() { return stack.get(stack.size() - 1); } public boolean isEmpty() { return stack.isEmpty(); } public int size() { return stack.size(); }

2)链表实现:

这里使用的 ListNode 有两个属性,如果是不使用 ListNode 的 next 属,就需要从 head 找到需要 peek 的 pre 节点,还需要进行循环判断找到 pre 节点(也就是需要 peek 的前一个)

▼
java
复制代码
private ListNode top; private int size = 0; public void push(Integer i) { top = new ListNode(i, top); size++; } public Integer pop() { if (top == null) { return null; } Integer val = top.val; top = top.next; size--; return val; } public Integer peek() { return top == null ? null : top.val; } public class ListNode { int val; ListNode next; ListNode() { } ListNode(int val) { this.val = val; } ListNode(int val, ListNode next) { this.val = val; this.next = next; } }

LeetCode 题目

image-20260830112609834

1)第一次做感觉用 Stack 还真是没有想到,一开始还以为这个 和 ([]) 是两种情况

2)更多的情况举一些具体的例子,来辅助:

输入 "()[]{}"

第一次:输入 ( ,栈 空

第二次:输入 ),栈 (,进行判断是否匹配,发现匹配就推出

等等

输入 "([)]"

第一次:输入 ( ,栈空

第二次:输入 [,栈 ( [

第三次:输入 ),栈 ([)

第四次:输入 ],栈 ([)]

最终栈还有 stack 有数据,就证明不匹配

输入 "([])"

第一次:输入 ( ,栈空

第二次:输入 [,栈 ([

第三次:输入 ],进行对比发现 stack.peek 元素和当前进行匹配,那么最终栈的元素 (

第四次:输入 ),进行对比发现 stack.peek 元素和当前进行匹配,那么最终栈的元素为空

最终栈的 stack 没有数据,证明是 valid 的

▼
java
复制代码
class Solution { private Map<Character, Character> map = new HashMap<>(); { map.put('(', ')'); map.put('[', ']'); map.put('{', '}'); } public boolean isValid(String s) { if (s.length() % 2 != 0) { return false; } Stack<Character> stack = new Stack<>(); char[] chars = s.toCharArray(); for (char aChar : chars) { if (!stack.isEmpty() && Objects.equals(aChar, map.get(stack.peek()))) { stack.pop(); continue; } stack.push(aChar); } return stack.isEmpty(); } }

Review

文章 https://www.3blue1brown.com/lessons/gpt 关于 LLM 是如何工作的。

关于 LLM 是如何工作的,有大佬是这样说的:

想象一下,有一些书,而书中有一个单词分隔符。这个单词分隔符总是保存某个单词在那个被分隔的单词之前出现了什么,并把它保存下来。通过概率和数学计算,LLM 使用这些分隔出来的单词进行训练,并尝试预测下一个单词是什么。所以在我给你的这个上下文中,这个单词分隔符会保存书中的每一个单词,以及哪个单词出现在它之前、哪个单词出现在它之后,例如“bread pudding”,然后是“new bread”,然后是“new bread is good”“too good!” 然后,当 LLM 收到问题“is bread pudding good?” 时,你会从你这里收到“pudim”“bread”和“good”这些词,并返回短语“bread pudding is good!”。这个例子很荒谬也很简单,但就是这么回事。

很荒谬但是 LLM 就是这样工作的,其实就像人脑的神经元也是一样的,一个很简单但是每一个连接起来就变得异常复杂,可以处理很多复杂的问题。

Tips

1)MacOS 不睡眠的命令:

▼
text
复制代码
caffeinate -d

2)用 pi 在需要 -p 的模式下还是挺好用的。比如批量校验文字是否有问题,可以用 Python 脚本 + pi 实现

3)语音转文字可以使用 whisper-cpp 搭配 large-v3-turbo 实现。

下载 whisper-cpp:

▼
text
复制代码
brew install whisper-cpp

下载模型:

注意:1)不要设置系统 proxy 2)需要设置 Token 获取链接

▼
text
复制代码
hf download ggerganov/whisper.cpp \ ggml-large-v3-turbo.bin

Share

文章:https://www.gingerbill.org/article/2026/01/02/was-it-really-a-billion-dollar-mistake/

「十亿美元错误」可能高估了 null 的问题。真正昂贵的,是「每个对象单独 new/free」的个体思维。

Tony Hoare 把空引用称为「十亿美元错误」,但 Odin 作者 gingerBill 认为,null 本身未必是最致命的问题。

在 C/Odin 里,空指针反而是最好发现、也相对少见的错误,更常见的是 use-after-free、指针运算错误和访问未映射内存。去掉 null,也只是把问题转移到「到处检查」或「强制初始化」上。

更深层的问题是内存管理方式:一个对象一个对象地分配和释放。

更合理的思路是把生命周期相同的数据放在一起,用 arena、pool、scratch (下面有介绍)这类方式批量管理。这样可以减少 malloc/free、减少指针和管理开销,也能避免大量无意义的逐对象初始化。

  • Arena:预先申请大块内存,统一分配,最后整体释放。
  • Pool:预先准备对象,需要时取出,用完后归还复用。
  • Scratch:专门存放临时数据,用完后一次性清空释放。

真正值得警惕的,可能不是 null,而是我们习惯把一组数据拆成一个个独立对象,然后逐个管理。

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
leikooo
作者分享
最近看了一个视频叫「被 Vibe Coding 抚平的大脑褶皱,还能救回来吗?」,聊的是 AI 时代学编程的困境,感觉说的挺好的,给鱼友们分享一下。 视频中提到现在学编程和以前最大的区别是,以前卡住了你只能自己想、查文档、翻 Stack Overflow,这个过程虽然痛苦,但你的脑子确实在转。现在有了 AI,卡住的第一反应就是打开 ChatGPT 问一句,代码瞬间就出来了,跑通了,感觉自己搞定了。但问题是,你的大脑在这个过程中几乎没有参与。视频里提到一个实验,有个学生读完题 10 秒钟就放弃思考去问 AI 了,事后还觉得是自己独立完成的。这就是 AI 带来的最大陷阱——你以为自己在学,其实只是在看AI 表演。 视频基于一项研究,总结了学编程时容易掉进去的 8 种思维陷阱。研究表明光是知道这些陷阱的存在,就能明显提升学习效果。前 5 种是编程学习中一直存在的,后 3 种是 AI 时代新出现的: 1)Forming(构建错误):你理解了问题,但用了错误的方法去解决。比如题目要你判断正数多还是负数多,你写了个求和的逻辑,方向对了路走偏了。 2)Dislodging(思维固着):你已经意识到方法不对,但就是转不过弯来换思路,反复在错误的方向上修修补补。 3)Assumption(假设偏差):你完美地解决了一个问题,但不是题目要求的那个问题。比如题目要处理任意个数字,你只处理了四个。4)Location(定位缺失):跳过了关键步骤就开始写代码,感觉快写完了,测试的时候才发现漏了循环或数据结构这种核心东西,得大改。 5)Achievement(成就幻觉):写了一大堆代码,明知道有问题但不愿意推倒重来,总想着再改改就好了,结果越改越乱。 6)Progression(进度错觉):AI 帮你写出了超出你水平的代码,作业都能交,但基础可能已经落后好几周了,自己完全不知道。这个是最危险的,等到面试或者独立写代码的时候才发现脑子里是空的。 7)Interruption(思维中断):你正在集中精力思考,AI 自动补全突然弹出来一段代码,思路直接被打断。有意思的是实验中表现好的学生大多直接忽略了 AI 的补全建议。 8)Mislead(误导跟随):信了 AI 给的一个看似合理但方向错误的建议,白白浪费时间走弯路。 大佬给出的建议是,遇到问题先别急着问 AI,给自己至少五分钟独立思考。卡住、沮丧、想摔键盘,这些不是你学不会的信号,这就是解决问题时的正常感受。AI 生成的代码跑通之后,试着关掉 AI 自己从零写一遍,能写出来才算真的会了。最重要的是分清场景,工作赶进度可以用 AI 提效,但练习和学习的时候请把「拐杖」放下,自己走。别让 AI 替你长脑子。
7
ARTS 0927: 单栈逐层展开嵌套字符串、包管理器与 Agent 沙箱本质同源与单次前向传播复刻极速决策模型
7
祝编程导航的鱼友们中秋快乐,愿代码顺利、生活如意,月圆人团圆,所愿皆可期!
13
ARTS 0913: 双栈互补实现队列、CIDR 聚合化解路由膨胀与 AI 作弊串通绝非偶然 Bug
8
微信爆出 P0 级漏洞😱,接到来电就中招,碰都不用碰手机。 怎么中招的? 黑客只需要是你的微信好友,然后给你打一个语音或视频通话,好了已经搞定了,你已经被黑了。 有多离谱? 完全不需要接这个电话。手机锁着屏扔在桌上,你看都没看一眼,只要响了几秒钟,恶意代码就已经在后台跑起来了。 黑客瞬间拿下你整个微信:翻你聊天记录、看你隐私、用你的身份给别人发消息。 更恐怖的是,你的微信紧接着会变成"丧尸",黑客可以自动给通讯录里所有好友挨个打电话,把他们也感染一遍。每个受害者又立刻变成新的传播者,像病毒一样指数级扩散...,不敢想象如果被利用了,理想情况下那需要多久就能扩散到全国的用户呢?30 分钟左右 好消息是这个 bug 微信团队已经知道了这个 bug ,坏消息这个 bug 好像不是微信团队发现的 文章来源:https://calif.io/research/weworm
7
下载 APP