avatar
文章
77
标签
219
分类
31
首页
简历
技术文章
时间图
分类
标签
关于
高晓庄 札记
首页
简历
技术文章
时间图
分类
标签
关于

高晓庄 札记

递归与回溯:从汉诺塔到全排列
发表于2026-02-16|基础
递归是很多人学习路上的一道坎。 它的反直觉之处在于:你没法在脑子里完整地展开整个递归过程,越想越晕。 但其实递归有套路可循,掌握了套路,就能”以不变应万变”。 递归的三要素任何递归问题,都必须明确三件事: 递归的定义:这个函数要做什么?(返回什么、有什么效果) 递归的终止条件:什么时候不再递归,直接返回? 递归的递推关系:怎么把大问题拆成子问题? 以经典的斐波那契为例: 1234int fib(int n) { if (n <= 1) return n; // 终止条件 return fib(n-1) + fib(n-2); // 递推关系} 想递归的正确姿势新手最容易犯的错,是在脑子里展开递归树——“fib(5) 调用 fib(4),fib(4) 又调用 fib(3)……”,然后彻底乱掉。 正确姿势是只关注当前这一层: 假设子问题已经解决了(相信递归) 只思考”怎么用子问题的结果,得到当前问题的结果” 然后补上终止条件 就像数学归纳法:假设 n-1 成立,证明 n 成立,再验证 n=1 成立。你不...
二分查找:边界条件为什么总是写错
发表于2026-02-13|基础
二分查找有个著名的梗:“一看就会,一写就错”。 甚至有人统计过,能一次写对二分查找的工程师不到 20%。 问题几乎全出在一个地方:边界条件。今天把它彻底讲透。 二分查找的前提二分查找只能用于有序数组(或单调序列)。 它的核心思想:每次取中间值,和目标比大小,直接排除一半。 1234567891011121314int binarySearch(int[] nums, int target) { int left = 0, right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] == target) { return mid; } else if (nums[mid] < target) { left = mid + 1; } else { ...
排序算法:快排、归并、堆排,理解比背诵重要
发表于2026-02-10|基础
排序算法大概是算法入门绕不开的第一课,也是面试里被问得最多的话题之一。 但很多人学排序的方式是”背代码”,结果背了忘、忘了背。 其实只要抓住每个算法的核心思想,代码自然就能写出来。 先记住这个底线基于比较的排序算法,时间复杂度有理论下界:O(n log n)。 也就是说,任何”靠比较大小来排序”的算法,最优也就是 O(n log n),不可能更快(除非用计数排序、桶排序这种不基于比较的特殊算法)。 所以快排、归并、堆排,都是已经摸到比较排序天花板的算法。 快速排序:分治 + 分区快排的核心是分区(partition):选一个”基准值(pivot)”,把数组分成两部分——左边都比 pivot 小,右边都比 pivot 大。然后对左右两部分递归做同样的事。 123456void quickSort(int[] arr, int lo, int hi) { if (lo >= hi) return; int p = partition(arr, lo, hi); // 分区,返回 pivot 位置 quickSort(arr, lo, p - 1);...
图与图的遍历:BFS、DFS 与拓扑排序
发表于2026-02-07|基础
前面讲的都是”线性”(数组、链表)和”层次”(树)结构。但现实中有大量关系是”网状”的: 社交网络里,谁关注谁 城市之间,怎么导航 项目里,任务之间的依赖 这些用树表达不了,因为树不允许”环”,而现实关系到处是环。这时候就需要图。 图的基本概念图由**顶点(Vertex)和边(Edge)**组成。 按边的方向,分为: 无向图:边没有方向(如”互为好友”) 有向图:边有方向(如”A 关注了 B”,单向) 按边是否带权重,分为: 无权图:边都一样 带权图:边有权重(如”两个城市之间的距离”) 图的两种存储方式1. 邻接矩阵用一个二维数组 matrix[i][j] 表示”从 i 到 j 是否有边”。 优点:判断”i 和 j 是否有边”是 O(1),简单直观 缺点:空间 O(n²),稀疏图(边很少)会浪费大量空间 2. 邻接表每个顶点维护一个”它指向的邻居”列表。 优点:空间 O(V + E),稀疏图很省 缺点:判断”i 和 j 是否有边”要遍历 i 的邻居列表,O(度数) 工程上邻接表更常用,因为现实中的图大多是稀疏的。 广度优先遍历(BFS)BFS 按”层”逐层向...
Docker 从入门到生产实践
发表于2026-02-05|Cloud NativeDocker
Docker 从入门到生产实践 Docker 的价值不在于”会跑一个容器”,而在于把”环境一致性”从口头承诺变成工程事实。本文聚焦真正影响生产环境的几个关键点。 镜像分层:缓存用对了,构建快 10 倍Dockerfile 的每一行指令都会生成一层。构建缓存能否命中,取决于指令和上下文是否变化。 一个反面例子: 1234# 差:每次代码变动都让 COPY 之后的层全部失效FROM openjdk:17COPY . /appRUN mvn package 依赖下载是构建中最慢的环节,却每次都要重跑。正确做法是先拷贝依赖清单,再拷贝源码: 123456FROM openjdk:17WORKDIR /appCOPY pom.xml .RUN mvn dependency:go-offlineCOPY src ./srcRUN mvn package -DskipTests 依赖层只有在 pom.xml 变化时才重建,日常改动源码时构建秒级完成。 镜像瘦身:从 800MB 到 120MB大镜像的问题不只是占磁盘,更影响部署速度——每台机器都要拉一遍。 瘦身三板斧: 多阶段构建:构建...
依赖注入:为什么你的代码不该自己 new 对象
发表于2026-02-02|基础
上一篇讲 SOLID 时,最后一条”依赖倒置原则(DIP)”是最难的。而依赖注入(DI)就是 DIP 的落地实现。 如果你用过 Spring,那你天天都在用 DI,只是可能没想过它背后的道理。 没有 DI 的世界先看一段”正常”的代码: 1234public class OrderService { private OrderRepository repository = new MySQLOrderRepository(); private EmailSender emailSender = new SmtpEmailSender();} 这段代码有什么问题? 强耦合:OrderService 直接依赖了具体实现 MySQLOrderRepository。要换数据库,就得改 OrderService。 难测试:想测试 OrderService,没法单独测,因为它内部硬绑定了真实的数据库和邮件服务。 重复创建:每个用到 OrderRepository 的类都自己 new 一个,浪费资源且状态难统一。 依赖注入的解法DI 的思路是:对象不再自己...
单元测试与 TDD:先写测试再写代码,真的值得吗
发表于2026-01-26|基础
写代码十年,我发现一个规律:越资深的工程师,越重视测试。 而新手最常见的误区是:觉得写测试是”额外负担”,是”拖慢进度”的事。 其实恰恰相反——测试是帮你提效的,不是给你添堵的。 为什么要写单元测试1. 让你敢重构没有测试的代码,重构就是赌博。你改了 A 处,可能偷偷破坏了 B 处,而你自己完全不知道。 有了测试,重构完跑一遍测试,全绿就说明行为没变。测试是重构的安全网。 2. 让 bug 更早暴露bug 越晚发现,修复成本越高。单元测试能在开发阶段就抓住大部分逻辑错误,而不是等到线上出问题才返工。 3. 测试本身就是文档一份好的测试用例,比注释更能说明”这段代码到底该怎么用、边界条件是什么”。 测试金字塔一个常见的分层模型: 1234567 /\ / \ E2E 测试(少,慢,贵) /----\ / \ 集成测试(中) /--------\ / \ 单元测试(多,快,便宜)/------------\ 原则:底层多写,顶层少写。 单元测试快、便宜、稳定,应该是主力。E2E 测试慢、贵、脆弱,只...
函数式编程范式:纯函数、不可变数据与高阶函数
发表于2026-01-24|基础
如果你长期写面向对象的代码,第一次接触函数式编程(FP)可能会觉得”别扭”。 但理解之后你会发现,它不是要取代面向对象,而是给了你另一种处理复杂问题的思维方式。 函数式编程的核心思想函数式编程有三个核心概念,理解了它们就抓住了 FP 的精髓。 1. 纯函数(Pure Function)纯函数满足两个条件: 同样的输入,永远得到同样的输出(确定性) 不产生任何副作用(不修改外部状态) 12345678910// 纯函数:输入相同,输出必然相同int add(int a, int b) { return a + b;}// 非纯函数:依赖并修改了外部状态int counter = 0;int increment() { return ++counter;} 为什么纯函数好?因为: 容易测试:不需要 mock 一堆状态 容易推理:看输入输出就能理解,不用追踪外部状态 天生线程安全:没有共享可变状态,就没有并发问题 2. 不可变数据(Immutability)函数式编程倾向于使用不可变数据:对象一旦创建,就永不改变。要”修改”...
1…78910
avatar
高晓庄
Java / Go / Python
AI / RAG / Agent
Cloud Native / Kubernetes
文章
77
标签
219
分类
31
Follow Me
最新文章
腾讯 Hy4 首发速评:770B 跑分该怎么读2026-11-04
众人熙熙,我独泊兮2026-10-25
本体论的学习:我们到底在学"什么"2026-10-18
把"想"这件事交给模型之后2026-10-14
当模型开始替你做决定2026-10-07
分类
  • AI33
    • Agent2
    • Architecture1
    • CV1
    • Dify1
    • LLM4
    • RAG1
  • Architecture3
标签
Dify API Spring 国产化 排序 混元 社会经济学 LangChain 虚拟化 本体论 注意力机制 数据结构 Kubernetes 个人成长 Go MetaGPT 向量检索 Spring Boot 容器化 智能问数 向量数据库 YOLOv5 认知 BFS Tool Use 回溯 CrewAI LLM Plan-and-Execute 算法 技术成长 TGI 大数据量 自由市场 AI编程 低代码 拓扑排序 佛学 BabyAGI 二叉树
归档
  • 2026-11 1
  • 2026-10 4
  • 2026-09 4
  • 2026-08 16
  • 2026-07 10
  • 2026-06 7
  • 2026-05 4
  • 2026-04 5
网站信息
文章数目 :
77
本站总字数 :
91.3k
本站访客数 :
本站总浏览量 :
最后更新时间 :
© 2025 - 2026 By 高晓庄