C++ 与 LeetCode 知识点¶
- 语言基础
- STL 容器与常用工具
- 常见数据结构
- 算法思想
1. 语言基础¶
1.1 基本类型 int / double / char / bool¶
是什么
int:整数,比如1、100double:小数,比如3.14char:单个字符,比如'A'bool:布尔值,只有true和false
怎么用
应用场景
int:数组下标、计数、答案double:平均值、几何题、精度计算char:字符串中的单个字符bool:条件判断、标记某件事是否成立
易错点
char用单引号,string用双引号bool输出时默认常显示成1或0int / int还是整数除法,比如3 / 2 = 1- 大数据范围时,
int可能不够,要考虑long long
记忆方法
int看成“整”double看成“双精度小数”char看成“一个字符”bool看成“真/假开关”
1.2 const 常量¶
是什么
const表示这个值定义后不允许修改
怎么用
应用场景
- 表示固定配置
- 保护函数参数不被修改
- 提高代码可读性和安全性
易错点
const变量定义后不能再赋值const vector<int>& nums里的const是“不能通过这个引用改内容”- 不要把“不能改引用指向”和“不能改引用内容”混在一起
记忆方法
const = constant = 常量 = 只读
1.3 引用 &¶
是什么
- 引用就是变量的“别名”
- 改引用,本质上就是改原变量
怎么用
应用场景
- 函数传参时避免拷贝大对象
- 在
for循环里直接修改容器元素 - 给已有变量起另一个名字
易错点
- 引用必须在定义时绑定,后面不能改绑到别的变量
int& ref = a;不是“复制”,而是“共享同一个值”const int&和int&不一样,前者不能改值
记忆方法
- 引用不是新盒子,而是给旧盒子贴了个新标签
1.4 指针 *¶
是什么
- 指针里存的是地址
*ptr才是这个地址指向的值
怎么用
应用场景
- 链表
- 二叉树
- 动态内存
- 函数中修改外部变量
易错点
int* ptr是定义指针,*ptr是解引用,不是一回事- 空指针
nullptr不能直接解引用 &x是取地址,*ptr是取地址里的值,方向别搞反
记忆方法
&是“拿到门牌号”*是“顺着门牌号找到屋里的人”
1.5 默认参数¶
是什么
- 调用函数时如果少传参数,就用函数定义里给的默认值
怎么用
应用场景
- 某个参数经常是固定值
- 想让函数调用更简洁
易错点
- 默认参数通常写在函数声明或定义里,只写一处
- 有默认值的参数一般放后面
- 调用时如果传了值,就不会再用默认值
记忆方法
- “你不说,我就按默认方案办”
1.6 值传递 / 引用传递 / 指针传递¶
是什么
- 值传递:传副本
- 引用传递:传原对象别名
- 指针传递:传地址
怎么用
void changeByValue(int x) { x = 100; }
void changeByReference(int& x) { x = 100; }
void changeByPointer(int* x) { *x = 100; }
应用场景
- 判断函数会不会改外部变量
- 优化参数传递效率
- 刷题时修改链表、树节点
易错点
- 值传递里改了参数,外部不变
- 指针传递前要先判断是不是
nullptr - 大对象如果值传递,会多一次拷贝
记忆方法
- 值传递:复印件
- 引用传递:同一个人
- 指针传递:给你地址你自己去找
1.7 template 模板¶
是什么
- 让同一份代码适配多种类型
怎么用
应用场景
- 写通用函数
- 写通用类
- 理解 STL 为什么能支持很多类型
易错点
- 模板参数类型要能支持你写的操作,比如这里要求能比较
> - 新手阶段常把模板想复杂,本质上就是“先不写死类型”
- 模板报错通常会比较长,要学会先看自己传入的类型是否匹配
记忆方法
- 模板就是“类型占位符”
1.8 struct¶
是什么
- 把几个相关变量打包成一个整体
怎么用
应用场景
- 学生信息
- 比赛记录
- 链表节点
- 树节点
易错点
struct里也可以有函数struct默认成员权限是public- 不要把“结构体”和“类”看成完全不同的东西,它们很像
记忆方法
struct = 打包数据
1.9 class¶
是什么
- 把“数据”和“操作数据的函数”封装在一起
怎么用
class Person
{
private:
string name;
int age;
public:
Person(string n, int a) : name(n), age(a) {}
};
应用场景
- 系统学习 C++ 面向对象
- 需要封装属性和行为
- 项目开发中组织复杂逻辑
易错点
class默认权限是private- 构造函数不是普通函数,它在对象创建时自动调用
private成员外部不能直接访问
记忆方法
class = 更讲封装的 struct
2. STL 容器与常用工具¶
2.1 vector¶
是什么
- 动态数组,长度可以自动变化
怎么用
应用场景
- 存一组数字
- 做题里最常见的顺序容器
- 图、前缀和、DP 数组等
易错点
nums[i]访问前要确保没越界- 空
vector不能直接访问nums[0] size()返回的是无符号类型,新手做减法时要小心
记忆方法
vector = 会自动长大的数组
2.2 sort¶
是什么
- STL 里的排序函数
怎么用
应用场景
- 排名
- 二分前预处理
- 去重前预处理
- 区间题、贪心题
易错点
- 排序默认是升序
- 区间写法是左闭右开,所以是
begin()到end() - 排序后原顺序会被打乱
记忆方法
- “先排好,再做题”
2.3 lambda 匿名函数¶
是什么
- 临时写在使用位置的小函数
怎么用
应用场景
- 自定义排序规则
- 临时比较逻辑
- 配合 STL 算法使用
易错点
return x > y;表示降序[]是捕获列表,新手先记住“这是 lambda 的一部分”- 写比较函数时要返回布尔值
记忆方法
- lambda = “现场写一个小函数”
2.4 string¶
是什么
- 字符串类型,本质上是字符序列
怎么用
应用场景
- 子串问题
- 回文串
- 模拟题
- 双指针字符串题
易错点
s[0]是字符,不是字符串- 注意越界,空字符串没有
s[0] size()返回长度,不是最后一个下标
记忆方法
string = 字符数组的升级版
2.5 pair¶
是什么
- 一次存两个值
怎么用
应用场景
- 坐标
(x, y) - 键值对
- 区间左右端点
易错点
first和second别写反- 两个值的类型可以不同
- 简单场景很好用,但数据更多时更适合
struct
记忆方法
pair = 绑定成一对
2.6 unordered_map¶
是什么
- 哈希表,存
key -> value
怎么用
应用场景
- 计数
- 映射
- 查重
- 两数之和
易错点
age["Tom"]如果不存在,会创建这个键- 只判断是否存在时,更建议用
count unordered_map遍历顺序不是有序的
记忆方法
- “拿 key,秒找 value”
2.7 set / unordered_set¶
是什么
set:自动去重,且有序unordered_set:自动去重,查找更快,但无序
怎么用
应用场景
- 去重
- 判重
- 判断某个值是否出现过
易错点
set会自动排序unordered_set不保证输出顺序- 两者都不会存重复元素
记忆方法
set = 去重集合unordered_set = 更快的去重集合
2.8 map¶
是什么
- 有序的
key -> value
怎么用
应用场景
- 需要按 key 顺序遍历
- 统计频次后有序输出
易错点
map一般比unordered_map慢一点map是按 key 排序,不是按 valuescoreMap["x"]不存在时也会新建
记忆方法
map = 有序版哈希表思路
2.9 stack¶
是什么
- 栈,后进先出
怎么用
应用场景
- 括号匹配
- 单调栈
- 模拟函数调用过程
易错点
pop()只弹出,不返回值- 取栈顶要用
top() - 空栈不能
top()或pop()
记忆方法
- 像一摞盘子,最后放的先拿
2.10 queue¶
是什么
- 队列,先进先出
怎么用
应用场景
- BFS
- 层序遍历
- 任务调度
易错点
front()取队头,不删除pop()删除队头,不返回值- 空队列不能直接
front()
记忆方法
- 像排队,先来的先处理
2.11 priority_queue¶
是什么
- 优先队列,默认大根堆
怎么用
应用场景
- Top K
- 每次取当前最大值
- 堆题
易错点
- 默认取最大,不是最小
pop()也不返回值- 如果要最小堆,需要额外写法
记忆方法
- “谁优先级高,谁先出来”
3. 常见数据结构¶
3.1 链表¶
是什么
- 每个节点存当前值和下一个节点地址
怎么用
应用场景
- 反转链表
- 删除节点
- 合并链表
- 快慢指针
易错点
- 容易把
next指向搞丢 - 改指针前要先保存下一节点
- 空链表要先判空
记忆方法
- 链表像“火车车厢”,每节只知道下一节
3.2 二叉树¶
是什么
- 每个节点最多有左孩子和右孩子
怎么用
应用场景
- 前序、中序、后序遍历
- 层序遍历
- 递归搜索
- 二叉搜索树
易错点
- 左右孩子容易写反
- 递归时要注意空节点
- 树题很多其实是在练递归返回值含义
记忆方法
- 树就是“会分叉的链表”
3.3 BFS 层序遍历¶
是什么
- 一层一层地访问节点,通常配合
queue
怎么用
应用场景
- 二叉树层序遍历
- 图的最短步数
- 从起点扩散搜索
易错点
- 忘了判空根节点
- 进队和出队顺序要清楚
- 题目要求“按层处理”时,常要记录当前层大小
记忆方法
- BFS = “一圈一圈往外扩”
4. 算法思想¶
4.1 双指针¶
是什么
- 用两个指针一起移动,减少重复遍历
怎么用
应用场景
- 有序数组
- 回文判断
- 移除元素
- 快慢指针
易错点
- 左右指针移动条件容易写错
- 边界要想清楚是
<还是<= - 指针什么时候移动,必须和题意绑定
记忆方法
- “一个人太慢,就两个人一起夹着找”
4.2 二分查找¶
是什么
- 在有序数组里每次看中间,砍掉一半区间
怎么用
应用场景
- 查目标值
- 找左边界/右边界
- 答案二分
易错点
- 前提通常是“有序”
mid推荐写成left + (right - left) / 2- 更新边界时很容易死循环
- 查值和查边界,写法不完全一样
记忆方法
- “每次砍半”
4.3 滑动窗口¶
是什么
- 用一个连续区间在数组或字符串上滑动
怎么用
应用场景
- 最长子串
- 最短子数组
- 连续区间统计
易错点
- 先扩右边还是先缩左边,逻辑要统一
- 窗口内维护的量要同步更新,比如
sum、计数器 - 不是所有子数组题都能用滑动窗口,通常要求某种单调性
记忆方法
- 像拿一个会移动的窗框去框住一段区间
4.4 前缀和¶
是什么
- 预处理前面所有元素的累计和
怎么用
应用场景
- 多次区间求和
- 子数组和
- 二维矩阵和
易错点
- 常见写法是
prefix长度比原数组大 1 - 区间
[l, r]的和通常是prefix[r + 1] - prefix[l] - 下标很容易错一位
记忆方法
- “前面先攒好,后面直接减”
4.5 DFS 递归¶
是什么
- 一条路先走到底,再回头换路
怎么用
应用场景
- 树遍历
- 图遍历
- 回溯搜索
易错点
- 一定要有结束条件
- 容易重复访问,图题常需要
visited - 递归层数太深可能爆栈
记忆方法
- DFS = “一路钻到底”
4.6 回溯¶
是什么
- 本质上是“带撤销的 DFS”
怎么用
应用场景
- 子集
- 排列
- 组合
- N 皇后
易错点
- 忘记撤销选择
pop_back() - 结果数组和当前路径数组别混
- 去重题通常要额外处理重复元素
记忆方法
- “试一下,不行就退回来”
4.7 贪心¶
是什么
- 每一步先做当前看起来最优的选择
怎么用
- 不一定有固定模板,关键是证明“局部最优能推出全局最优”
应用场景
- 跳跃游戏
- 区间覆盖
- 分发饼干
- 股票部分题型
易错点
- 不是“看起来合理”就一定能贪心
- 贪心题难点通常不是写代码,而是想清楚策略为什么对
- 局部最优不一定总能推出全局最优
记忆方法
- “先拿眼前最划算的”
4.8 动态规划¶
是什么
- 把大问题拆成小问题,当前答案由之前状态推出来
怎么用
常见思考顺序:
dp[i]表示什么- 状态转移方程是什么
- 初始值是什么
- 遍历顺序是什么
应用场景
- 爬楼梯
- 背包问题
- 最长上升子序列
- 编辑距离
易错点
- 最容易错的是
dp[i]的定义不清 - 初始值不对,后面全错
- 遍历顺序可能影响结果
- 别把 DP 和递归硬混,先写清状态
记忆方法
- “今天的答案,靠昨天和前天推出来”
5. 刷题时的使用建议¶
5.1 看到题先想什么¶
- 是不是数组 / 字符串题
- 能不能排序
- 有没有哈希表优化
- 是不是连续区间,可以考虑滑动窗口或前缀和
- 是不是树 / 图,考虑 DFS 或 BFS
- 是不是最值或计数,考虑动态规划
5.2 新手最容易混的几组¶
引用和指针stack::top()和pop()queue::front()和pop()map和unordered_mapset和unordered_setDFS和回溯贪心和动态规划
5.3 一份推荐学习顺序¶
- 先把
vector、string、unordered_map、sort学熟 - 再学
stack、queue、set、map - 然后进
链表、二叉树 - 最后主攻
双指针、二分、滑动窗口、DFS、BFS、回溯、贪心、DP
6. 总结¶
如果把这份笔记压缩成一句话:
- 语言基础解决“代码怎么写”
- STL 容器解决“数据怎么存”
- 数据结构解决“题目对象长什么样”
- 算法思想解决“题目怎么做”