引言:为什么LeetCode刷题是C++面试的关键
在当今的软件开发行业,尤其是进入大厂(如Google、Facebook、Amazon、Microsoft等)的面试过程中,算法题是不可或缺的一部分。LeetCode作为全球最大的算法题库平台,提供了海量的编程题目,帮助求职者准备技术面试。对于C++开发者来说,刷LeetCode不仅仅是练习语法,更是掌握高效解题技巧、理解数据结构和算法本质的过程。
C++作为一种高效、灵活的系统编程语言,在大厂面试中备受青睐。面试官通常会考察候选人对C++特性的理解(如STL容器、智能指针、多态等),以及如何用C++实现高效的算法。通过系统刷题,你可以从入门级的简单题入手,逐步攻克中等难度题,最终精通高频题型,如数组、字符串、链表、树、图、动态规划等。这不仅能提升你的编码能力,还能帮助你在面试中自信应对白板编程或在线编码环境。
本指南将从入门到精通,提供一个结构化的刷题路径,包括学习资源、高频题型分类、解题技巧,以及详细的C++代码示例。无论你是初学者还是有经验的开发者,都能从中获益。记住,刷题的核心是理解而非死记硬背:多思考时间复杂度(O(n))、空间复杂度(O(1)),并练习用C++的STL来简化代码。
入门阶段:打好基础,熟悉LeetCode平台
1.1 选择合适的入门资源和工具
入门阶段的目标是熟悉LeetCode平台、C++语法和基本数据结构。不要急于求成,先花1-2周时间掌握基础。
推荐资源
:
LeetCode官网:注册账号,从“Explore”卡片开始,如“Learn”中的“Top Interview Questions”集合。这些题目是面试高频入门题。
C++书籍:《Effective C++》(Scott Meyers)和《C++ Primer》(Stanley Lippman)来复习语法。
在线课程:Coursera的“Algorithms, Part I” by Princeton(用Java讲解,但可转C++)或Bilibili上的C++算法视频。
工具:使用Visual Studio Code + C++扩展,或CLion进行本地调试。LeetCode支持C++17,确保代码兼容。
刷题策略
:
每天1-2题,从Easy难度开始。
先独立思考10-15分钟,再看题解。
用C++提交时,注意使用
#include
、
#include
等STL头文件。
练习输出:理解输入输出格式,LeetCode通常用函数签名如
int func(vector
。
1.2 基础数据结构复习
在刷题前,快速复习C++ STL中的基础容器:
数组/向量
:
vector
,动态大小,支持随机访问。
字符串
:
string
,支持拼接、子串操作。
链表
:自定义节点结构体,或用
std::list
(但面试常自定义)。
栈/队列
:
stack
、
queue
,用于DFS/BFS。
示例:简单数组题 – Two Sum(LeetCode 1)
题目:给定整数数组nums和目标target,返回两个数的索引,使它们和为target。
解题思路:用哈希表(unordered_map)存储值到索引的映射,时间复杂度O(n)。
#include
#include
using namespace std;
class Solution {
public:
vector
unordered_map
for (int i = 0; i < nums.size(); ++i) {
int complement = target - nums[i];
if (hash.find(complement) != hash.end()) {
return {hash[complement], i};
}
hash[nums[i]] = i;
}
return {}; // 无解
}
};
详细说明
:
主题句
:哈希表允许O(1)查找,避免O(n^2)的暴力双重循环。
支持细节
:
unordered_map
是C++ STL的哈希实现,插入和查找平均O(1)。注意边界:数组可能有重复元素,但题目保证唯一解。测试用例:输入
[2,7,11,15]
,target=9,输出
[0,1]
。
技巧
:在面试中,先解释暴力解法(双重for循环,O(n^2)),再优化到哈希。练习时,用
cout
调试输出中间值。
入门阶段目标:完成50道Easy题,熟悉STL使用。常见陷阱:忘记处理空数组或负数。
进阶阶段:掌握高频题型与解题技巧
2.1 高频题型分类
进入中级(Medium难度),聚焦面试高频主题。LeetCode的“Top 100 Liked Questions”是绝佳起点。目标:每天2-3题,积累模板代码。
数组与字符串
:滑动窗口、双指针。
链表
:快慢指针、反转。
树
:二叉树遍历(前序、中序、后序)、BST操作。
图
:BFS/DFS、最短路径。
回溯与递归
:组合、排列问题。
排序与搜索
:二分查找、快速排序。
2.2 解题技巧通用框架
四步法
:1. 理解问题(输入输出、约束)。2. 想出多种解法(暴力→优化)。3. 写代码(C++风格:用引用避免拷贝)。4. 优化(分析复杂度,用
std::move
减少开销)。
C++特有技巧
:
用
auto
简化迭代器。
智能指针
unique_ptr
管理内存(面试中避免raw指针)。
Lambda表达式:如
sort(nums.begin(), nums.end(), [](int a, int b){ return a < b; });
。
时间管理
:面试中,Medium题控制在20-30分钟。练习时,用LeetCode的“Playground”测试边缘case。
示例:滑动窗口 - Minimum Window Substring(LeetCode 76)
题目:给定字符串s和t,返回s中包含t所有字符的最小子串。
解题思路:用两个指针维护窗口,哈希表记录t的字符需求,滑动窗口扩展/收缩。
#include
#include
#include
using namespace std;
class Solution {
public:
string minWindow(string s, string t) {
if (s.empty() || t.empty()) return “”;
unordered_map
for (char c : t) need[c]++;
int required = need.size(); // 不同字符数
int left = 0, right = 0;
int formed = 0; // 窗口中满足需求的字符数
unordered_map
int minLen = INT_MAX, minStart = 0;
while (right < s.size()) {
char c = s[right];
window[c]++;
if (need.count(c) && window[c] == need[c]) formed++;
// 收缩窗口
while (left <= right && formed == required) {
if (right - left + 1 < minLen) {
minLen = right - left + 1;
minStart = left;
}
char leftChar = s[left];
window[leftChar]--;
if (need.count(leftChar) && window[leftChar] < need[leftChar]) formed--;
left++;
}
right++;
}
return minLen == INT_MAX ? "" : s.substr(minStart, minLen);
}
};
详细说明
:
主题句
:滑动窗口将时间复杂度从O(n^2)优化到O(n),适用于子串/子数组问题。
支持细节
:
unordered_map
用于O(1)计数检查。
required
和
formed
确保窗口包含t的所有字符。测试:s=“ADOBECODEBANC”, t=“ABC”,输出”BANC”。
技巧
:面试中,先画图说明窗口移动。优化:如果t很长,可用数组代替map(ASCII码范围)。常见错误:忘记更新
formed
导致无限循环。
2.3 链表与树的技巧
链表
:用
struct ListNode { int val; ListNode* next; };
定义。技巧:dummy节点避免头节点特殊处理。
示例:Reverse Linked List(LeetCode 206)。用迭代法,时间O(n),空间O(1)。
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(nullptr) {}
};
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr) {
ListNode* next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
return prev;
}
};
说明
:用三个指针(prev, curr, next)实现原地反转。面试中解释递归版(空间O(n))作为对比。
树
:用
struct TreeNode { int val; TreeNode* left; TreeNode* right; };
。
示例:Validate Binary Search Tree(LeetCode 98)。中序遍历应递增。
#include
#include
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class Solution {
public:
bool isValidBST(TreeNode* root) {
if (!root) return true;
stack
TreeNode* curr = root;
long long prev = LLONG_MIN; // 用long long避免int溢出
while (curr || !s.empty()) {
while (curr) {
s.push(curr);
curr = curr->left;
}
curr = s.top(); s.pop();
if (curr->val <= prev) return false;
prev = curr->val;
curr = curr->right;
}
return true;
}
};
说明
:中序遍历用栈模拟递归,避免递归栈溢出。技巧:用
long long
处理边界(如INT_MIN)。
进阶阶段目标:完成100道Medium题,形成解题模板。参考“Grind 75”计划,按周分类刷。
精通阶段:攻克难题与优化
3.1 高频难题型
动态规划(DP)
:子序列、背包问题。技巧:自底向上表格法,或记忆化递归。
图算法
:Dijkstra最短路径、Union Find。
位运算与数学
:如Bitwise AND of Numbers Range(LeetCode 201)。
3.2 优化与面试策略
复杂度分析
:用Master Theorem分析递归树。C++中,用
std::priority_queue
实现优先队列。
面试模拟
:练习白板写代码,解释思路。常见大厂题:Merge Intervals(区间合并)、LRU Cache(设计题,用双向链表+哈希表)。
示例:动态规划 – Longest Increasing Subsequence(LeetCode 300)
题目:返回数组中最长严格递增子序列长度。
解题思路:DP数组
dp[i]
表示以nums[i]结尾的LIS长度。优化:用二分查找维护tails数组,时间O(n log n)。
#include
#include
using namespace std;
class Solution {
public:
int lengthOfLIS(vector
if (nums.empty()) return 0;
vector
for (int num : nums) {
auto it = lower_bound(tails.begin(), tails.end(), num);
if (it == tails.end()) {
tails.push_back(num);
} else {
*it = num;
}
}
return tails.size();
}
};
详细说明
:
主题句
:二分查找优化将O(n^2) DP降到O(n log n),适用于序列问题。
支持细节
:
lower_bound
是C++ STL的二分函数,返回第一个>=num的位置。tails保持递增,确保LIS性质。测试:[10,9,2,5,3,7,101,18],输出4([2,3,7,101])。
技巧
:面试中,先写O(n^2)版:双重循环更新dp。优化后解释tails的作用。常见陷阱:严格递增需
<
而非
<=
。
精通阶段目标:攻克50道Hard题,掌握10+模板。阅读《算法导论》或LeetCode题解,分析他人代码。
高级技巧与资源推荐
4.1 C++面试专属优化
STL高级用法
:
std::set
用于去重排序,
std::map
用于计数。避免深拷贝:用
const vector
传参。
内存管理
:用
vector
代替数组,避免内存泄漏。面试中,解释RAII(Resource Acquisition Is Initialization)。
多线程基础
:虽算法题少涉及,但了解
std::thread
和
mutex
加分。
4.2 常见错误与调试
错误
:越界访问(用
at()
代替
[]
)、未初始化变量。
调试
:用GDB或LeetCode的调试器。打印中间状态:
for(auto x: vec) cout<