Skip to content

第二阶段:计算机基础强化(8.11 - 8.24,2周)

学习目标

夯实数据结构与算法基础,掌握操作系统核心概念,能够应对字节跳动面试中的算法手撕题和计算机基础八股文。目标:LeetCode 中等难度稳定 AC,操作系统高频考点能完整口述。


模块一:数据结构(Day 1-3)

1.1 数组与链表

必须掌握的知识点:

  • 数组:连续内存、O(1) 随机访问、O(n) 插入删除
  • 链表:非连续内存、O(n) 访问、O(1) 插入删除(已知位置)
  • 单链表、双链表、循环链表
  • 哨兵节点(dummy head)简化边界处理
  • Go 中 slice 底层就是数组;链表需手动实现

高频面试题(必刷):

题目LeetCode难度考点
反转链表206Easy指针操作
合并两个有序链表21Easy双指针
环形链表 II142Medium快慢指针
删除链表倒数第N个节点19Medium快慢指针
两数相加2Medium链表遍历
合并K个升序链表23Hard分治/堆
LRU 缓存146Medium双向链表+哈希表

八股文要点:

  • "数组和链表的区别?各自适用场景?"
  • "如何检测链表有环?如何找到环的入口?" → Floyd 判圈法
  • "如何在 O(1) 时间删除链表节点?" → 值覆盖法

1.2 栈与队列

必须掌握的知识点:

  • 栈:LIFO,Go 用 slice 模拟(append + 截取)
  • 队列:FIFO,Go 用 slice 或 container/list
  • 单调栈:维护单调递增/递减序列,解决"下一个更大元素"类问题
  • 单调队列:滑动窗口最大值
  • 优先队列(堆):Go 的 container/heap 接口

高频面试题:

题目LeetCode难度考点
有效的括号20Easy
最小栈155Medium辅助栈
每日温度739Medium单调栈
滑动窗口最大值239Hard单调队列
前K个高频元素347Medium
用栈实现队列232Easy双栈

八股文要点:

  • "栈和队列的区别?各自的典型应用场景?"
  • "如何用两个栈实现队列?时间复杂度?" → 均摊 O(1)
  • "单调栈解决什么类型的问题?时间复杂度?"

1.3 哈希表

必须掌握的知识点:

  • 哈希函数:将 key 映射到数组下标
  • 冲突解决:
    • 链地址法(Go map 使用)
    • 开放寻址法(线性探测、二次探测)
  • 负载因子:元素数/桶数,Go map 的负载因子阈值 6.5
  • 扩容:翻倍 + rehash(Go 是渐进式迁移)
  • Go map 不可并发读写(第一阶段已学)

高频面试题:

题目LeetCode难度考点
两数之和1Easy哈希查找
字母异位词分组49Medium哈希分组
最长连续序列128Medium哈希集合
无重复字符的最长子串3Medium哈希+滑窗

八股文要点:

  • "哈希冲突的解决办法有哪些?各自优缺点?"
  • "HashMap 的扩容机制?为什么是 2 的幂次?" → 位运算取模
  • "一致性哈希是什么?解决什么问题?" → 分布式场景

1.4 树

必须掌握的知识点:

  • 二叉树遍历:前序、中序、后序、层序(递归 + 迭代)
  • BST(二叉搜索树):中序有序、查找/插入/删除 O(logn)~O(n)
  • 平衡树概念:AVL、红黑树(面试只需知道性质和应用场景)
  • 堆:完全二叉树、最大堆/最小堆、上浮/下沉操作
  • 前缀树(Trie):字符串前缀匹配

高频面试题:

题目LeetCode难度考点
二叉树的层序遍历102MediumBFS
翻转二叉树226Easy递归
二叉树的最大深度104EasyDFS
验证二叉搜索树98Medium中序遍历
二叉树的最近公共祖先236Medium递归
二叉树的右视图199MediumBFS
前K个高频元素347Medium
实现 Trie208Medium前缀树

八股文要点:

  • "红黑树的五个性质?为什么 Go 没有在 map 中用红黑树?" → 链地址法 + 溢出桶更适合 Go 的设计
  • "堆排序的时间复杂度?为什么不如快排常用?" → 缓存不友好
  • "B 树和 B+ 树的区别?为什么数据库用 B+ 树?" → 叶子节点链表,范围查询高效

1.5 图

必须掌握的知识点:

  • 表示方法:邻接矩阵、邻接表
  • BFS:层序遍历、最短路径(无权图)
  • DFS:连通性、拓扑排序、回溯
  • 拓扑排序:入度法(Kahn)/ DFS 后序反转
  • 最短路径:Dijkstra(单源)、Floyd(多源)— 了解即可
  • 并查集:连通分量、判断是否有环

高频面试题:

题目LeetCode难度考点
岛屿数量200MediumDFS/BFS
课程表207Medium拓扑排序
课程表 II210Medium拓扑排序
腐烂的橘子994Medium多源BFS
克隆图133MediumDFS+哈希

八股文要点:

  • "DFS 和 BFS 的区别?各自适用什么场景?"
  • "拓扑排序用来解决什么问题?时间复杂度?"
  • "如何检测图中是否有环?有向 vs 无向?"

模块二:算法(Day 4-9)

2.1 排序算法

必须掌握的知识点:

算法时间(平均)时间(最坏)空间稳定性
冒泡排序O(n²)O(n²)O(1)稳定
插入排序O(n²)O(n²)O(1)稳定
选择排序O(n²)O(n²)O(1)不稳定
快速排序O(nlogn)O(n²)O(logn)不稳定
归并排序O(nlogn)O(nlogn)O(n)稳定
堆排序O(nlogn)O(nlogn)O(1)不稳定

必须手写:快速排序、归并排序

go
// 快速排序 - 必须能15分钟内手写
func QuickSort(arr []int, left, right int) {
    if left >= right {
        return
    }
    pivot := partition(arr, left, right)
    QuickSort(arr, left, pivot-1)
    QuickSort(arr, pivot+1, right)
}

func partition(arr []int, left, right int) int {
    pivot := arr[right]
    i := left
    for j := left; j < right; j++ {
        if arr[j] < pivot {
            arr[i], arr[j] = arr[j], arr[i]
            i++
        }
    }
    arr[i], arr[right] = arr[right], arr[i]
    return i
}

// 归并排序
func MergeSort(arr []int) []int {
    if len(arr) <= 1 {
        return arr
    }
    mid := len(arr) / 2
    left := MergeSort(arr[:mid])
    right := MergeSort(arr[mid:])
    return merge(left, right)
}

func merge(left, right []int) []int {
    result := make([]int, 0, len(left)+len(right))
    i, j := 0, 0
    for i < len(left) && j < len(right) {
        if left[i] <= right[j] {
            result = append(result, left[i])
            i++
        } else {
            result = append(result, right[j])
            j++
        }
    }
    result = append(result, left[i:]...)
    result = append(result, right[j:]...)
    return result
}

八股文要点:

  • "快排为什么平均是 O(nlogn),最坏是 O(n²)?如何优化?" → 随机 pivot / 三数取中
  • "快排和归并的区别?" → 快排原地、不稳定;归并稳定、需额外空间
  • "什么是排序稳定性?什么场景需要稳定排序?"
  • "Go 的 sort.Sort 用什么算法?" → pdqsort(Go 1.19+),混合排序

2.2 二分查找

必须掌握的知识点:

  • 基本模板:左闭右闭 [left, right]
  • 变体:
    • 查找第一个等于 target 的位置(lower_bound)
    • 查找最后一个等于 target 的位置(upper_bound - 1)
    • 查找第一个大于等于 target 的位置
  • 关键:循环不变量,明确搜索区间
go
// 标准二分 - 左闭右闭
func BinarySearch(nums []int, target int) int {
    left, right := 0, len(nums)-1
    for left <= right {
        mid := left + (right-left)/2
        if nums[mid] == target {
            return mid
        } else if nums[mid] < target {
            left = mid + 1
        } else {
            right = mid - 1
        }
    }
    return -1
}

// 查找左边界
func LowerBound(nums []int, target int) int {
    left, right := 0, len(nums)-1
    for left <= right {
        mid := left + (right-left)/2
        if nums[mid] < target {
            left = mid + 1
        } else {
            right = mid - 1
        }
    }
    return left
}

高频面试题:

题目LeetCode难度考点
搜索旋转排序数组33Medium二分变体
在排序数组中查找元素的第一个和最后一个位置34Medium左右边界
搜索插入位置35Easy基本二分
寻找峰值162Medium二分
搜索二维矩阵240Medium二分思想

2.3 双指针与滑动窗口

必须掌握的知识点:

  • 对撞指针:两端向中间(有序数组两数之和、回文判断)
  • 快慢指针:链表环检测、链表中间节点
  • 滑动窗口:
    • 固定窗口:窗口大小不变
    • 可变窗口:满足条件时收缩
    • 模板:右指针扩张 → 条件满足 → 左指针收缩
go
// 滑动窗口模板
func SlidingWindow(s string) int {
    window := make(map[byte]int)
    left := 0
    result := 0
    for right := 0; right < len(s); right++ {
        c := s[right]
        window[c]++
        // 条件不满足时收缩
        for /* 窗口需要收缩的条件 */ {
            d := s[left]
            window[d]--
            left++
        }
        // 更新结果
        result = max(result, right-left+1)
    }
    return result
}

高频面试题:

题目LeetCode难度考点
三数之和15Medium排序+双指针
盛最多水的容器11Medium对撞指针
无重复字符的最长子串3Medium滑窗
最小覆盖子串76Hard滑窗
找到字符串中所有字母异位词438Medium固定滑窗
长度最小的子数组209Medium滑窗

2.4 递归与回溯

必须掌握的知识点:

  • 递归三要素:终止条件、递归逻辑、返回值
  • 回溯模板:选择 → 递归 → 撤销选择
  • 剪枝:提前终止无效搜索路径
  • 常见应用:排列、组合、子集、N皇后
go
// 回溯模板
func backtrack(path []int, choices []int, result *[][]int) {
    if /* 满足结束条件 */ {
        tmp := make([]int, len(path))
        copy(tmp, path)
        *result = append(*result, tmp)
        return
    }
    for i, choice := range choices {
        // 剪枝
        if /* 不满足约束 */ {
            continue
        }
        path = append(path, choice) // 做选择
        backtrack(path, choices[i+1:], result) // 递归
        path = path[:len(path)-1] // 撤销选择
    }
}

高频面试题:

题目LeetCode难度考点
全排列46Medium回溯
组合总和39Medium回溯+剪枝
子集78Medium回溯
电话号码的字母组合17Medium回溯
括号生成22Medium回溯+剪枝
N 皇后51Hard回溯

2.5 动态规划

必须掌握的知识点:

  • DP 五步法:
    1. 定义状态(dp[i] 代表什么)
    2. 状态转移方程
    3. 初始化
    4. 遍历顺序
    5. 返回值
  • 常见类型:
    • 线性 DP:爬楼梯、打家劫舍
    • 背包问题:0-1 背包、完全背包
    • 区间 DP:最长回文子串
    • 序列 DP:最长递增子序列、最长公共子序列
    • 二维 DP:路径问题

高频面试题:

题目LeetCode难度考点
爬楼梯70Easy基础DP
最长递增子序列300Medium序列DP
零钱兑换322Medium完全背包
最长公共子序列1143Medium二维DP
编辑距离72Medium二维DP
打家劫舍198Medium线性DP
不同路径62Medium二维DP
单词拆分139MediumDP+哈希
最长回文子串5Medium区间DP

八股文要点:

  • "动态规划和贪心的区别?" → DP 枚举所有子问题取最优,贪心只看局部最优
  • "如何判断一个问题能不能用 DP?" → 最优子结构 + 重叠子问题
  • "背包问题的空间优化?" → 滚动数组 / 一维压缩

2.6 贪心算法

必须掌握的知识点:

  • 核心思想:每步选择局部最优,期望全局最优
  • 适用条件:贪心选择性质 + 最优子结构
  • 证明方法:交换论证法(面试不要求严格证明)

高频面试题:

题目LeetCode难度考点
跳跃游戏55Medium贪心
跳跃游戏 II45Medium贪心
无重叠区间435Medium区间贪心
合并区间56Medium排序+贪心
分发糖果135Hard两次遍历贪心

2.7 BFS/DFS 综合

必须掌握的知识点:

  • BFS 模板(层序遍历):队列 + visited
  • DFS 模板:递归 / 显式栈
  • 矩阵搜索:四方向移动 dx = [0,0,1,-1]
  • 多源 BFS:多个起点同时入队
go
// BFS 模板(图/矩阵搜索)
func bfs(grid [][]int, startX, startY int) {
    rows, cols := len(grid), len(grid[0])
    visited := make([][]bool, rows)
    for i := range visited {
        visited[i] = make([]bool, cols)
    }
    
    queue := [][]int{{startX, startY}}
    visited[startX][startY] = true
    dirs := [][]int{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}
    
    for len(queue) > 0 {
        cur := queue[0]
        queue = queue[1:]
        for _, d := range dirs {
            nx, ny := cur[0]+d[0], cur[1]+d[1]
            if nx >= 0 && nx < rows && ny >= 0 && ny < cols &&
                !visited[nx][ny] && grid[nx][ny] == 1 {
                visited[nx][ny] = true
                queue = append(queue, []int{nx, ny})
            }
        }
    }
}

模块三:操作系统(Day 10-14)

3.1 进程与线程

必须掌握的知识点:

进程

  • 定义:程序的一次执行实例,是资源分配的基本单位
  • 状态:创建 → 就绪 → 运行 → 阻塞 → 终止
  • 进程控制块(PCB):进程ID、状态、程序计数器、寄存器、内存映射、打开的文件
  • 进程间通信(IPC):
    • 管道(pipe):半双工,父子进程
    • 命名管道(FIFO):无亲缘关系进程
    • 消息队列:内核维护的消息链表
    • 共享内存:最快的 IPC 方式(需要同步机制)
    • 信号量(semaphore):计数器,用于进程同步
    • Socket:网络通信,最通用

线程

  • 定义:CPU 调度的基本单位,共享进程的地址空间
  • 线程 vs 进程:
    • 进程有独立地址空间,线程共享
    • 线程切换成本 < 进程切换(不需要切换页表)
    • 线程间通信更方便(共享内存),但需要同步
  • 用户态线程 vs 内核态线程:
    • 用户态:协程/goroutine,调度在用户空间
    • 内核态:OS 线程,由内核调度
    • Go 的模型:M:N(多个 goroutine 映射到多个 OS 线程)

协程(对应 Go 的 goroutine)

  • 更轻量:KB 级栈空间 vs 线程 MB 级
  • 用户态调度:无需系统调用
  • 适合 I/O 密集型场景

八股文要点:

  • "进程和线程的区别?"
  • "进程间通信有哪些方式?各自的优缺点?"
  • "为什么线程切换比进程切换快?" → 不需要切换地址空间(页表)、TLB 不失效
  • "协程的优势是什么?Go 的 goroutine 和一般协程有什么区别?" → 可被抢占、可并行(多 M)
  • "僵尸进程和孤儿进程是什么?怎么处理?"

3.2 CPU 调度

必须掌握的知识点:

  • 调度目标:公平性、吞吐量、响应时间、CPU 利用率
  • 常见调度算法:
    • FCFS(先来先服务):简单但可能导致"护航效应"
    • SJF(最短作业优先):平均等待时间最短,但可能饥饿
    • 时间片轮转(RR):公平,时间片大小影响性能
    • 优先级调度:可抢占/不可抢占
    • 多级反馈队列(MLFQ):Linux CFS 的基础思想
  • Linux CFS(完全公平调度器):
    • 基于虚拟运行时间(vruntime)
    • 红黑树管理就绪队列
    • 选择 vruntime 最小的进程运行
  • 上下文切换:
    • 保存/恢复 CPU 寄存器、程序计数器、栈指针
    • 切换页表(进程切换时)
    • 刷新 TLB(进程切换时)

八股文要点:

  • "什么是上下文切换?开销在哪里?"
  • "Linux 用什么调度算法?CFS 怎么保证公平?"
  • "时间片设多大合适?设太大/太小各有什么问题?"

3.3 内存管理

必须掌握的知识点:

虚拟内存

  • 每个进程有独立的虚拟地址空间(32 位:4GB,64 位:极大)
  • 虚拟地址 → 物理地址:通过页表映射
  • 好处:
    • 进程隔离(互不影响)
    • 超过物理内存的程序也能运行(swap)
    • 共享内存(多进程映射同一物理页)

分页机制

  • 页(Page):虚拟内存的基本单位,通常 4KB
  • 页框(Frame):物理内存的基本单位
  • 页表:虚拟页号 → 物理页框号
  • 多级页表:减少页表内存占用(只分配用到的部分)
  • TLB(Translation Lookaside Buffer):
    • 页表的高速缓存
    • 命中:1 个时钟周期
    • 未命中:访问内存中的页表(数十~数百周期)

页面置换算法

  • OPT(最优置换):替换未来最长时间不用的页(理想,不可实现)
  • FIFO(先进先出):可能 Belady 异常(增加页框反而更多缺页)
  • LRU(最近最少使用):替换最久未使用的页(实际常用近似实现)
  • Clock(时钟算法):LRU 的近似,用访问位循环扫描
  • LFU(最不经常使用):替换访问次数最少的页

进程地址空间布局

高地址
┌─────────────┐
│   内核空间    │
├─────────────┤
│     栈       │ ← 向下增长
│     ↓       │
│             │
│     ↑       │
│     堆       │ ← 向上增长(malloc/new)
├─────────────┤
│   BSS 段     │ ← 未初始化全局变量
├─────────────┤
│   数据段     │ ← 已初始化全局变量
├─────────────┤
│   代码段     │ ← 只读,可共享
└─────────────┘
低地址

八股文要点:

  • "什么是虚拟内存?为什么需要虚拟内存?"
  • "页表是什么?多级页表解决什么问题?"
  • "TLB 是什么?为什么进程切换要刷新 TLB?"
  • "LRU 怎么实现?时间复杂度?" → HashMap + 双向链表,O(1)
  • "malloc 的底层实现?" → 小块 brk(堆扩展),大块 mmap
  • "栈和堆的区别?" → 栈自动管理/连续/快;堆手动管理/碎片/慢
  • "什么是内存泄漏?Go 中怎么排查?" → pprof heap profile

3.4 文件系统与 I/O

必须掌握的知识点:

文件系统

  • inode:存储文件元数据(权限、大小、时间、数据块指针)
  • 目录:特殊文件,存储 文件名→inode 的映射
  • 硬链接 vs 软链接:
    • 硬链接:多个文件名指向同一 inode
    • 软链接:一个文件存储另一个文件的路径(类似快捷方式)
  • 文件系统类型:ext4、XFS、ZFS

I/O 模型(Linux)

  • 阻塞 I/O:进程阻塞直到数据就绪
  • 非阻塞 I/O:立即返回,轮询检查
  • I/O 多路复用:
    • select:fd 数量有限(1024),每次需要遍历所有 fd
    • poll:无数量限制,但仍需遍历
    • epoll:事件驱动,O(1) 获取就绪 fd,Go 网络底层使用
      • epoll_create:创建 epoll 实例
      • epoll_ctl:注册/修改/删除监听事件
      • epoll_wait:等待事件就绪
      • 两种触发模式:LT(水平触发)、ET(边缘触发)
  • 信号驱动 I/O
  • 异步 I/O(AIO):内核完成后通知进程

零拷贝

  • 传统读写:磁盘 → 内核缓冲区 → 用户缓冲区 → Socket 缓冲区 → 网卡(4 次拷贝)
  • sendfile:磁盘 → 内核缓冲区 → 网卡(2 次拷贝,零用户态拷贝)
  • mmap:将文件映射到用户空间,减少一次拷贝

八股文要点:

  • "select、poll、epoll 的区别?"
  • "epoll 的 LT 和 ET 有什么区别?" → LT 只要就绪就通知;ET 仅状态变化时通知一次
  • "为什么 Go 的网络 I/O 能做到高并发?" → goroutine + netpoller(epoll)
  • "什么是零拷贝?应用场景?"
  • "inode 是什么?一个文件的 inode 包含哪些信息?"

3.5 锁与同步

必须掌握的知识点:

锁的类型

  • 互斥锁(Mutex):同一时刻只有一个线程持有
  • 读写锁(RWMutex):多读一写
  • 自旋锁(Spinlock):忙等待,适合临界区极短的场景
  • 乐观锁 vs 悲观锁:
    • 悲观锁:先加锁再操作(Mutex)
    • 乐观锁:先操作再检查冲突(CAS)

死锁

  • 四个必要条件:
    1. 互斥:资源不能共享
    2. 持有并等待:持有资源的同时请求新资源
    3. 不可剥夺:已持有的资源不能被强制回收
    4. 循环等待:存在资源请求的环形链
  • 解决方法:
    • 预防:破坏四个条件之一(如固定加锁顺序破坏循环等待)
    • 避免:银行家算法(检查安全状态)
    • 检测:资源分配图
    • 恢复:杀死进程 / 回滚

原子操作

  • CAS(Compare-And-Swap):if *addr == old { *addr = new; return true }
  • Go 的 sync/atomic 包:AddInt64CompareAndSwapInt64LoadInt64StoreInt64
  • ABA 问题:值从 A→B→A,CAS 认为没变。解决:加版本号

八股文要点:

  • "死锁的四个条件?怎么避免?"
  • "CAS 是什么?有什么问题?" → ABA 问题、自旋开销、只能保护一个变量
  • "互斥锁和自旋锁的区别?什么时候用自旋锁?" → 临界区极短(< 几μs)
  • "Go 的 Mutex 有哪两种模式?" → 正常模式(自旋+竞争)和饥饿模式(FIFO)

3.6 网络基础(必考)

必须掌握的知识点:

TCP/IP 分层模型

应用层:HTTP、DNS、FTP
传输层:TCP、UDP
网络层:IP、ICMP、ARP
数据链路层:以太网
物理层

TCP 三次握手

客户端          服务端
  |--- SYN(seq=x) --->|      第一次:客户端发起连接请求
  |<-- SYN+ACK(seq=y, ack=x+1) --|  第二次:服务端确认并请求连接
  |--- ACK(ack=y+1) -->|      第三次:客户端确认
  • 为什么三次?→ 防止失效的连接请求到达服务端导致资源浪费

TCP 四次挥手

主动方          被动方
  |--- FIN --->|          第一次:主动方请求关闭
  |<-- ACK ----|          第二次:被动方确认
  |<-- FIN ----|          第三次:被动方也请求关闭
  |--- ACK --->|          第四次:主动方确认
  [TIME_WAIT 2MSL]
  • 为什么四次?→ TCP 全双工,每个方向需要单独关闭
  • 为什么 TIME_WAIT?→ 确保最后一个 ACK 到达 + 让旧连接的报文消散

TCP 可靠性保证

  • 序列号 + 确认号
  • 超时重传(RTO)
  • 滑动窗口(流量控制)
  • 拥塞控制:慢启动 → 拥塞避免 → 快重传 → 快恢复

TCP vs UDP

特性TCPUDP
连接面向连接无连接
可靠性可靠(重传、排序)不可靠
速度较慢较快
场景HTTP、文件传输DNS、视频流、游戏

HTTP

  • HTTP/1.1:持久连接、管线化(但有队头阻塞)
  • HTTP/2:多路复用、头部压缩、服务端推送、二进制帧
  • HTTP/3:基于 QUIC(UDP)、解决 TCP 队头阻塞
  • HTTPS = HTTP + TLS:
    • TLS 握手:非对称加密交换密钥 → 对称加密通信
    • 证书验证:CA 签名、证书链

DNS

  • 域名 → IP 地址的解析
  • 递归查询 vs 迭代查询
  • 缓存层级:浏览器 → OS → 本地DNS → 根DNS → 顶级域DNS → 权威DNS

八股文要点:

  • "TCP 三次握手的过程?为什么不是两次/四次?"
  • "TCP 四次挥手?TIME_WAIT 的作用?TIME_WAIT 过多怎么办?"
  • "TCP 怎么保证可靠传输?"
  • "TCP 和 UDP 的区别?各自适用场景?"
  • "HTTP/1.1、HTTP/2、HTTP/3 的演进?解决了什么问题?"
  • "HTTPS 的加密过程?"
  • "输入 URL 到页面显示的全过程?" → DNS → TCP → HTTP → 渲染

模块四:八股文速查卡片

数据结构与算法八股

#问题核心答案
1数组 vs 链表数组连续内存O(1)随机访问;链表非连续O(1)增删
2HashMap 原理数组+链表/红黑树;哈希定位+链地址法解冲突
3红黑树用在哪Java HashMap(>8)、Linux CFS、C++ map
4B+树为什么适合数据库叶子有序链表适合范围查询;扇出大减少I/O
5堆的应用TopK、优先队列、堆排序
6快排最坏情况已排序数组+固定pivot → O(n²),用随机pivot优化
7DP vs 贪心DP枚举所有子问题取全局最优;贪心取局部最优
8DFS vs BFSDFS用栈/递归深度优先;BFS用队列广度优先找最短路

操作系统八股

#问题核心答案
1进程 vs 线程进程=资源分配单位(独立地址空间);线程=调度单位(共享地址空间)
2协程优势用户态调度、KB级栈、创建成本极低、适合I/O密集
3死锁条件互斥+持有等待+不可剥夺+循环等待,破坏任一可预防
4虚拟内存进程独立地址空间,页表映射到物理内存,提供隔离+超额分配
5页面置换LRU最常考:HashMap+双向链表实现O(1);Clock是近似LRU
6select vs epollselect:O(n)遍历+1024限制;epoll:事件驱动O(1)+无限制
7TCP可靠性序列号+确认+重传+滑动窗口+拥塞控制
8三次握手原因防止失效SYN到达服务端建立无效连接浪费资源
9TIME_WAIT2MSL等待:确保最后ACK到达+旧报文消散
10HTTPS加密非对称密钥交换(RSA/ECDHE)→ 对称加密通信(AES)
11零拷贝sendfile/mmap避免用户态拷贝,用于文件传输/消息队列
12CAS比较并交换,乐观锁实现;ABA问题用版本号解决

每日学习计划

天数主题上午(3h)下午(3h)晚上(2h)
Day 1数组/链表学习数据结构原理LeetCode 刷题 5-6 道整理八股笔记
Day 2栈/队列/哈希表学习原理 + 单调栈LeetCode 刷题 5-6 道面试题模拟
Day 3树/图二叉树遍历+BSTLeetCode 刷题 5-6 道堆/Trie/图论
Day 4排序/二分手写快排归并LeetCode 二分题 5 道面试题模拟
Day 5双指针/滑窗学习模板LeetCode 刷题 6 道复习
Day 6回溯学习模板+剪枝LeetCode 回溯题 5 道面试题模拟
Day 7动态规划(上)线性DP+背包LeetCode DP 题 5 道复习
Day 8动态规划(下)序列DP+二维DPLeetCode DP 题 5 道面试题模拟
Day 9贪心/BFS/DFS贪心+图搜索LeetCode 综合刷题算法总复习
Day 10进程/线程/协程学习原理整理八股文对比Go的goroutine
Day 11CPU调度/同步调度算法+锁死锁+CAS面试题模拟
Day 12内存管理虚拟内存+分页页面置换+地址空间复习
Day 13I/O与文件系统I/O模型+epoll零拷贝+文件系统面试题模拟
Day 14网络TCP/UDP/HTTPDNS+HTTPS全阶段总复习

LeetCode 刷题计划(总计 70+ 题)

第一周:数据结构 + 基础算法(Day 1-5)

  • 链表:206, 21, 142, 19, 2, 23, 146 → 7 题
  • 栈/队列:20, 155, 739, 239, 347, 232 → 6 题
  • 哈希:1, 49, 128, 3 → 4 题
  • 树:102, 226, 104, 98, 236, 199, 208 → 7 题
  • 二分:33, 34, 35, 162, 240 → 5 题
  • 双指针/滑窗:15, 11, 76, 438, 209 → 5 题

第二周:高级算法 + OS(Day 6-9)

  • 回溯:46, 39, 78, 17, 22, 51 → 6 题
  • DP:70, 300, 322, 1143, 72, 198, 62, 139, 5 → 9 题
  • 贪心:55, 45, 435, 56, 135 → 5 题
  • 图/BFS/DFS:200, 207, 210, 994, 133 → 5 题
  • 综合练习:补刷弱项 → ~10 题

合计约 70 题(配合第一阶段已有的并发编程练习代码)


推荐学习资源

算法

操作系统

八股文复习


阶段验收标准

完成以下全部内容视为通过第二阶段:

  • [ ] 能手写快速排序和归并排序(10 分钟内)
  • [ ] 能手写二分查找及左右边界变体(5 分钟内)
  • [ ] 能手写 BFS/DFS 模板(5 分钟内)
  • [ ] 能手写滑动窗口模板(5 分钟内)
  • [ ] LeetCode 中等难度正确率 > 70%(限时 30 分钟)
  • [ ] 能口述进程/线程/协程区别及 Go 的 M:N 模型
  • [ ] 能口述虚拟内存 + 分页 + TLB 完整机制
  • [ ] 能口述 TCP 三次握手/四次挥手全过程及原因
  • [ ] 能口述 select/poll/epoll 区别及 Go netpoller 原理
  • [ ] 能口述死锁四条件 + 解决方案
  • [ ] 能画出进程地址空间布局图
  • [ ] 能解释 HTTP/1.1 → HTTP/2 → HTTP/3 的演进动机

持续学习,持续构建。