☰
从0备战大厂Day01:复杂度分析与数组哈希表实战
2026/10/15 4:51:35 网站建设 项目流程

晚上十一点,办公楼里该走的都走了。我把手头项目的最后一个接口联调完,关掉调试工具,打开了一个新的文档,敲下标题:从0开始进军大厂-Day01。

说实话,这不算我第一次动这个念头。过去三年里,我买过算法书、收藏过学习路线、甚至试听过某训练营的免费课,但每次都停在"等手头工作轻松点再开始"的阶段。结果就是三年过去了,手头工作从来没轻松过,收藏夹倒是越来越满。

这次不太一样。我把过去几年写过的代码、做过的项目重新翻了一遍,发现自己能拿得出手的,只有CRUD和接口联调这种"熟练工"的活儿。再往下追问底层原理、复杂度分析、工程优化,脑子里就只剩一团浆糊。继续等下去,差距只会越来越大。所以我决定开一个系列,把每天的准备过程原原本本记下来,用公开记录逼自己往前走。

这篇文章就是Day01的完整复盘,内容包括:我为什么把自己定义为"从0开始"、第一天的目标到底该怎么定、我学到的第一个算法知识点、以及当天实操里踩到的三个坑。如果你也在准备冲大厂,但还停留在"收藏了就等于会了"的阶段,这篇应该能给你一点参考。

1. 为什么启动这场"从0到大厂"的长期记录

1.1 先交代背景:我到底是一个什么样的"0"

说"从0开始",其实不完全是自谦。我工作四年了,日常用Java和Python写业务代码,CRUD、接口联调、跟产品拉扯需求,这些我都熟。但"熟练"和"扎实"之间有一条明显的鸿沟。

举个例子。之前组里做技术分享,有人随口问我一句:"HashMap的底层结构到底是什么?为什么它查找那么快?"我当场愣住,憋了半天只说出"好像是数组加链表吧",再往下问"什么时候会转成红黑树""为什么阈值是8",我就完全接不上了。

这件事对我的触动很大。我意识到,我脑子里的知识都是零零散散的碎片,面试官随便从一个点往下追问两层,我就会露出马脚。我所说的"0",指的不是不会写代码,而是没有一个成体系的知识结构。所以Day01的第一件事,不是马上去刷第一道题,而是先承认这个"0"的存在,再想怎么把它填上。

1.2 大厂到底在考什么:先把技术维度拆开

在定计划之前,我花了不少时间研究头部互联网公司的面试经验分享,把它们整理成了一个框架。到技术终面为止,考察的内容大体上可以分成四块:

  • 编码基础:数据结构、算法、操作系统、计算机网络、数据库、语言底层机制。这是硬功底,也是最容易一票否决的环节。
  • 项目深度:你做过什么、遇到了什么问题、怎么排查、怎么优化,考察的是真实的工程能力和思考习惯。
  • 系统设计:给一个开放场景让你做方案设计,考察架构思维、边界意识和对量级的感知。
  • 软素质:沟通表达、抗压能力、学习意愿,这部分往往被低估,但在跨部门协作和大团队里特别重要。

Day01这个阶段,我的注意力主要放在第一块里的数据结构和算法上,因为这是最可量化、也最容易被卡住的一道关。项目深度和系统设计,我打算放在后面的Day系列里用专门的复盘文章来补,一口吃不成胖子,但每一口都得吃在关键位置上。

1.3 这个系列打算怎么写

我给自己定了几条原则,写在这里当约束:

  • 每天都记录,但重点写"思考过程",而不是贴一堆最终答案。
  • 每篇至少讲清楚三件事:今天做了什么、踩了什么坑、明天准备怎么做。
  • 进度宁慢勿快,不追求一天刷十道题,追求的是每道题都能独立讲明白。
  • 尽量把学到的东西用大白话复述一遍,复述得出来才算真懂。

这篇文章就是这个系列的第一篇,也是我给自己上的第一道紧箍咒:写出来,就没有回头路。后面不管加班多晚,我都会尽量保持更新,至少把当天的笔记和心得沉淀下来。

2. Day01的第一件事:不做题,先做能力盘点和目标拆解

2.1 对照目标岗位要求拆解硬性条件

以前我备战的方式,就是打开刷题网站,今天做两道,明天做三道,想到什么做什么。最后的结果是每种题型都见过一点,但没一个能拿得出手。这次我换了顺序,先找到自己理想岗位的类型——后端开发岗,然后把它常见的高频考察点列成一张表,再给自己的现状打分。

这张表是Day01最重要的产出之一,我贴出来供参考:

考察模块高频考点我的当前水平
数据结构数组、链表、栈、队列、树、图、哈希表、堆数组链表能写,树和图很生疏
算法思想排序、二分、递归、动态规划、贪心、回溯排序会几种,动态规划基本不会
语言机制集合类源码、并发、IO、内存模型会日常使用,原理说不清
操作系统/网络进程线程、内存管理、TCP/IP、HTTP概念都见过,深问就卡壳
数据库索引、事务、锁、调优索引了解,锁机制待补
项目/设计项目难点、系统设计、扩展性有项目但欠缺总结提炼

填完这张表,我最大的感受是:以前总觉得"我好像什么都该学",现在变成了"我具体缺什么、缺多少"一目了然。后面所有的学习安排,都应该是从这张表倒推出来的,而不是兴致来了学什么就学什么。

2.2 给自己定下的四阶段路线

量化完差距之后,我把整个备战周期分成了四个阶段,每个阶段都有明确的目标和结束时的验收标准:

  1. 地基期(约6周):主攻数据结构和基础算法,每学一个主题,都要能徒手写出对应代码并讲清复杂度。
  2. 进阶期(约6周):主攻动态规划、回溯、贪心这些进阶算法,配合刷题量巩固,每天至少完成一道中等难度题目。
  3. 专项期(约4周):回头补齐操作系统、网络、数据库、语言机制这些计算机基础,用八股题和场景题交替检验。
  4. 冲刺期(约4周):做模拟面试、复盘项目、整理错题集,重点是训练在45分钟内完整给出解法的节奏感。

四个阶段加起来大概20周,也就是差不多五个月。这是我认为一个基础一般的在职开发者比较现实的时间周期。如果有人跟你说"两周速通大厂算法",那要么他本来就是名校科班出身,要么就是准备收割你的焦虑。我宁可把周期拉长一点,也不愿意学个半吊子就上考场。

2.3 每天两小时的时间切分

对于还要上班的人来说,整块时间非常奢侈。我现在的作息是这样:晚上九点半以后,一天的杂事基本处理完,从九点半到十一点半,是雷打不动的两个小时。我把这两个小时切成三段:

  • 前40分钟:学习新知识点。看资料、做笔记,重点是理解"为什么",而不是记结论。
  • 中间40分钟:针对刚学的知识点,手写一到两道例题。写不出来就翻笔记,但翻完必须合上再写。
  • 最后40分钟:复盘整理。把当天卡壳的地方记到错题本上,顺手写下第二天的学习计划。

周末会额外补一个上午,用来做阶段小测验,检验这一周到底真正掌握了多少。这个节奏不快,但它的优势是可持续。我见过太多人第一周打鸡血每天刷三小时,第二周就开始断档,第三周直接放弃。我不想重蹈覆辙,所以宁可每天只学两小时,也要坚持到最后一刻。

3. 算法地基第一课:复杂度分析与数组的底层认知

3.1 为什么开篇第一课是复杂度

很多人学算法,第一件事是去背快速排序怎么写、链表怎么反转。但我觉得对大多数人来说,第一课应该是时间复杂度和空间复杂度。因为后面所有题目的优化,本质上都是在和复杂度作斗争。

我见过一些候选人,代码能跑通,但当面试官问"你这个解法时间复杂度是多少"时,只能回答"应该挺快的"。这种回答基本等于送分题变送命题。时间复杂度的定义其实不复杂:它描述的是当输入规模n不断变大时,算法运行时间的增长趋势。注意,是趋势,不是精确的耗时。同样的算法,在快机器上跑1秒,在慢机器上跑3秒,这不影响它的复杂度。

复杂度分析是算法面试的通用语言。面试官说"能不能优化到O(n)",你立刻要意识到他是在说:你的O(n²)解法不够好,需要用哈希表、双指针或者排序等手段把循环层数降下来。不懂这门语言,后面所有的讨论都进行不下去。

3.2 数组在内存里到底是什么样

数组是所有数据结构的入门,也是最容易被低估的一个。它的本质是一段连续的、固定大小的内存空间。因为连续,所以系统可以通过"起始地址 + 索引 × 每个元素大小"这一个公式,直接算出任意元素的内存地址,访问时间恒定为O(1)。这是数组最大的优势,也是它"随机访问"特性的来源。

但同一个"连续"特性,也会带来代价。想在数组中间插入或删除一个元素时,你没法直接"腾个位置",因为后面的元素地址都是紧挨着的。你只能把后面的元素逐个往后挪或往前挪,操作次数跟元素数量成正比,复杂度是O(n)。这里面的因果链很重要:连续内存带来O(1)的随机访问,也带来O(n)的插入删除。

理解了这一点,你后面学链表时会有一种"原来是这么回事"的通透感。链表用不连续的内存节点,每个节点存下一个节点的地址,所以插入删除只需要改一下指针,O(1);但访问某个节点只能从头往后一个个找,O(n)。两种结构为什么各有取舍,答案全藏在内存布局里。

3.3 用生活化的例子把常见复杂度刻进脑子里

我习惯把复杂度对应到现实场景里,这样不容易忘,也方便给别人讲:

  • O(1):打开冰箱门,直接拿起放在最外层的那瓶水。不管冰箱里有多少东西,拿它用的时间差不多。
  • O(n):在一摞完全没整理过的账单里找某一张,倒霉的话要从头翻到尾,账单越多,时间线性增长。
  • O(n²):双层循环的典型场景。比如一群朋友两两握手,n个人一共握n*(n-1)/2次手,大约就是n²。数据量翻倍,时间变四倍。
  • O(log n):1到100的猜数字游戏,每次被告知"大了还是小了",每次都排除一半,最多7次就能锁定答案。数据量翻倍,只多一次。

把这几个例子记熟之后,再看到代码,我就会下意识地去找循环嵌套层数、有没有在循环里查找、能不能用哈希表把查找变成O(1)。这种敏感度不是天生的,就是靠一遍遍练出来的。

3.4 第一天手写的两道题:完整思考过程

理论学完,得落到代码上。我今天选了数组和哈希表方向的两道经典入门题。

第一道是数组去重。最朴素的解法是双重遍历,每遇到一个新元素,就回头检查之前有没有出现过,时间复杂度O(n²)。优化思路是引入哈希集合:遍历时把元素放入集合,集合天然能判断"这个值是否已经存在",整体降到O(n)。代码如下:

def deduplicate(nums): seen = set() result = [] for num in nums: if num not in seen: seen.add(num) result.append(num) return result

第二道是两数之和:给定一个数组和一个目标值,找出数组中两个和为target的元素的下标。看到这道题,新手几乎条件反射就是双重循环,两层嵌套把所有组合试一遍,O(n²):

def two_sum_brutal(nums, target): for i in range(len(nums)): for j in range(i + 1, len(nums)): if nums[i] + nums[j] == target: return [i, j] return [-1, -1]

这道题的经典优化是引入哈希表。核心思路是:遍历每个数字时,不是去"找它的另一半",而是把"它期望的另一半是多少"记下来。当前数字num,期望的另一半就是target - num。如果这个期望值之前已经被某个数字登记过,说明这两个数字凑成了一对,直接返回下标。

def two_sum(nums, target): need = {} for i, num in enumerate(nums): if num in need: return [need[num], i] need[target - num] = i return [-1, -1]

写这两道题的时候,我刻意做了一件事:先在纸上把遍历过程一步步画出来,再动笔写代码。画第二遍时,我突然理解了为什么是"把补数存进哈希表"而不是"把原数存进去"——因为当你遍历到一个新数字时,你要快速回答的问题是"我之前有没有遇到过它的另一半",所以哈希表的key是"期望匹配的那个数",value是"这个期望来自哪个下标"。这一个视角转换,就是这道题的精髓所在,光看不画是体会不到的。

4. Day01实操复盘:三个坑和三个收获

4.1 坑一:没看清限制条件就上手写码

做两数之和时,我第一遍直接写了暴力循环,等写完才发现题目背后有一堆隐藏假设:数组无序、可能有重复值、只要求返回一组答案。这些限制条件不是摆设,它们直接决定了最优解是什么。

如果数组是排序好的,那双指针就能搞定;如果不允许用额外空间,哈希表方案直接作废;如果要求返回所有答案,还得考虑去重。把这些边界想清楚再动手,写出来的代码价值完全不同。面试官不会只看最终代码对不对,他更在意你的审题过程。很多经验帖都会强调,拿到题目先花一分钟确认输入规模、边界条件和输出要求,再开口说思路。我Day01就因为没有做这一步,白费了二十分钟,虽然最后还是写出来了,过程却乱得很。

4.2 坑二:把"看懂了"当成"会写了"

以前我学算法最大的毛病,是看视频、看题解时"嗯嗯嗯原来如此",合上笔记本就觉得掌握了,结果第二天一道简单的变形题就能把我打回原形。今天我特意测试了自己的真实水平:看完两数之和的题解后,合上资料重新写一遍。

结果写出来的第一版是有bug的——我在查哈希表时,忘了判断查到的value是不是当前下标本身。比如target是6,数组中恰好有一个3,我在遍历到第一个3时,会试图查找"是否有人登记过正好缺3",而此时哈希表里还没有任何记录;但等我遍历到第二个3时,哈希表里已经存了第一个3的补数3,而那个补数的value就是第一个3的下标,被我误判成了一对答案。这种边界情况,光看题解是绝对看不出来的。

这让我对"会了"的标准有了新的定义:真正的会,是关上所有参考资料,从零开始独立写出来,并且能解释清楚每一步为什么这样做。看懂的阈值和写对的阈值之间,隔着好几遍练习的距离。

4.3 我给刻意练习定的三条规则

针对上面的教训,我给自己的刷题过程定了三条硬性规则,后面每天都要按这个流程走:

  • 规则一:先用自己的话复述题意,说清楚输入是什么、输出是什么、有哪些边界条件,确认没有理解偏差再动手。
  • 规则二:先写伪代码思路,再翻译成真实代码。写完必须手动跑三个测试用例,包括一个正常用例、一个空输入、一个极端情况。
  • 规则三:代码通过后,强制自己独立说出时间复杂度和空间复杂度分别是多少,说不出来就当作没学会。

这三条规则看起来简单,真的坚持下来挺难的。Day01我只完整走通了一套流程,但明显感觉到,这样学一道题,比以前囫囵吞枣看十道题都要扎实。刚开始会慢,但慢就是快。

4.4 首日成果清单与Day02的安排

最后清点一下Day01的产出:

  • 完成了一份能力盘点表,明确了六个知识模块的现状和缺口。
  • 制定了一个20周的四阶段备战路线,并拆解到每天的时间切片。
  • 搞懂了时间复杂度和空间复杂度的核心逻辑,能独立分析简单的循环嵌套。
  • 理解了数组连续内存的本质,以及它和链表之间取舍的根本原因。
  • 手写并调试通过了两道数组/哈希表入门题,同时暴露并修正了一个边界bug。

Day02的计划这会已经写在笔记本上了:继续数据结构模块,进入链表章节,重点对比链表和数组在插入、删除、访问上的复杂度差异;再把两数之和的三种变形各写一遍——有序数组版(用双指针)、多组答案版(要处理重复)、空间受限版(不能用哈希表)。

数据结构这种东西,学一天看不出差距,学一周能感到有些概念开始串起来了,学一两个月才会有明显的质变。但前提是,你真的能坚持到那一天。

第一天最深的感受是:准备大厂这件事,最大的敌人从来不是知识难度,而是自己的三天热度。这个系列我会继续写下去,每一篇都尽量真实地记录当天的进度和问题,包括走了多少弯路、踩了多少坑。如果未来某天我真的拿到了理想的offer,回头看这些文字,那一定比结果本身更有价值。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询