尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

C++后端面试必刷10大算法题与优化技巧

C++后端面试必刷10大算法题与优化技巧 1. 项目概述作为一名在C后端开发领域摸爬滚打多年的老程序员我深知算法能力在大厂面试中的重要性。这期内容我将分享10道高频出现的C后端面试算法题并附上经过生产环境验证的代码实现。这些题目覆盖了字符串处理、链表操作、树形结构、动态规划等核心考点都是我在实际面试中遇到过或作为面试官经常考察的题目。2. 核心算法题解析2.1 单链表逆置链表逆置是考察指针操作的基础题目但能很好地检验候选人对内存管理的理解。经典实现需要三个指针prev、current和next。struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(nullptr) {} }; ListNode* reverseList(ListNode* head) { ListNode* prev nullptr; ListNode* curr head; while (curr) { ListNode* nextTemp curr-next; curr-next prev; prev curr; curr nextTemp; } return prev; }注意事项边界条件处理很重要特别是空链表和单节点链表的情况。在实际工程中建议加上输入参数检查。2.2 二叉树层序遍历层序遍历BFS是树结构中的基础算法在文件系统遍历、网络爬虫等场景都有应用。使用队列实现时要注意节点入队顺序。struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} }; vectorvectorint levelOrder(TreeNode* root) { vectorvectorint result; if (!root) return result; queueTreeNode* q; q.push(root); while (!q.empty()) { int levelSize q.size(); vectorint currentLevel; for (int i 0; i levelSize; i) { TreeNode* node q.front(); q.pop(); currentLevel.push_back(node-val); if (node-left) q.push(node-left); if (node-right) q.push(node-right); } result.push_back(currentLevel); } return result; }2.3 快速排序实现快速排序是工程中最常用的排序算法之一平均时间复杂度O(nlogn)。注意分区函数的实现和递归终止条件。int partition(vectorint nums, int left, int right) { int pivot nums[right]; int i left - 1; for (int j left; j right; j) { if (nums[j] pivot) { i; swap(nums[i], nums[j]); } } swap(nums[i 1], nums[right]); return i 1; } void quickSort(vectorint nums, int left, int right) { if (left right) { int p partition(nums, left, right); quickSort(nums, left, p - 1); quickSort(nums, p 1, right); } }实操心得在实际项目中当数组较小时如n15可以切换为插入排序STL的sort就是这么优化的。3. 进阶算法题目3.1 LRU缓存实现LRULeast Recently Used缓存是系统设计中的经典问题结合哈希表和双向链表可以达到O(1)时间复杂度。class LRUCache { private: struct Node { int key, value; Node *prev, *next; Node(int k, int v) : key(k), value(v), prev(nullptr), next(nullptr) {} }; int capacity; unordered_mapint, Node* cache; Node *head, *tail; void addToHead(Node* node) { node-prev head; node-next head-next; head-next-prev node; head-next node; } void removeNode(Node* node) { node-prev-next node-next; node-next-prev node-prev; } void moveToHead(Node* node) { removeNode(node); addToHead(node); } Node* removeTail() { Node* res tail-prev; removeNode(res); return res; } public: LRUCache(int capacity) : capacity(capacity) { head new Node(-1, -1); tail new Node(-1, -1); head-next tail; tail-prev head; } int get(int key) { if (!cache.count(key)) return -1; Node* node cache[key]; moveToHead(node); return node-value; } void put(int key, int value) { if (cache.count(key)) { Node* node cache[key]; node-value value; moveToHead(node); } else { Node* node new Node(key, value); cache[key] node; addToHead(node); if (cache.size() capacity) { Node* removed removeTail(); cache.erase(removed-key); delete removed; } } } };3.2 最长递增子序列动态规划解法时间复杂度O(n²)二分查找优化版可以达到O(nlogn)是动态规划的经典案例。int lengthOfLIS(vectorint nums) { vectorint dp(nums.size(), 1); for (int i 1; i nums.size(); i) { for (int j 0; j i; j) { if (nums[i] nums[j]) { dp[i] max(dp[i], dp[j] 1); } } } return *max_element(dp.begin(), dp.end()); } // 二分查找优化版 int lengthOfLISOpt(vectorint nums) { vectorint tails; 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(); }4. 海量数据处理专题4.1 Top K问题在海量数据中找出前K大/小的元素堆结构是最佳选择。下面给出使用优先队列的实现vectorint topKFrequent(vectorint nums, int k) { unordered_mapint, int freq; for (int num : nums) freq[num]; priority_queuepairint, int, vectorpairint, int, greaterpairint, int pq; for (auto [num, count] : freq) { pq.push({count, num}); if (pq.size() k) { pq.pop(); } } vectorint res; while (!pq.empty()) { res.push_back(pq.top().second); pq.pop(); } return res; }性能分析时间复杂度O(nlogk)空间复杂度O(n)。当k远小于n时效率很高适合处理海量数据。4.2 布隆过滤器实现布隆过滤器是处理海量数据去重的利器特点是空间效率极高但有一定误判率。class BloomFilter { private: vectorbool bits; vectorfunctionsize_t(string) hashFuncs; size_t size; public: BloomFilter(size_t size, size_t numHashes) : size(size) { bits.resize(size, false); for (size_t i 0; i numHashes; i) { hashFuncs.push_back([this, i](string key) { size_t hash 0; for (char c : key) { hash (hash * 131 c) % this-size; } return (hash i) % this-size; }); } } void add(const string key) { for (auto hashFunc : hashFuncs) { bits[hashFunc(key)] true; } } bool contains(const string key) { for (auto hashFunc : hashFuncs) { if (!bits[hashFunc(key)]) { return false; } } return true; } };5. 系统设计相关算法5.1 线程安全的生产者消费者模型使用C11的mutex和condition_variable实现这是后端开发必须掌握的多线程编程模式。class BlockingQueue { private: queueint q; mutex mtx; condition_variable cv; int maxSize; public: BlockingQueue(int size) : maxSize(size) {} void put(int value) { unique_lockmutex lock(mtx); cv.wait(lock, [this]() { return q.size() maxSize; }); q.push(value); cv.notify_all(); } int take() { unique_lockmutex lock(mtx); cv.wait(lock, [this]() { return !q.empty(); }); int value q.front(); q.pop(); cv.notify_all(); return value; } };5.2 一致性哈希算法分布式系统中常用的数据分片算法能有效解决节点增减时的数据迁移问题。class ConsistentHash { private: mapsize_t, string circle; hashstring hashFunc; int virtualNodeNum; public: ConsistentHash(int vnum 100) : virtualNodeNum(vnum) {} void addNode(const string node) { for (int i 0; i virtualNodeNum; i) { string vnode node # to_string(i); size_t key hashFunc(vnode); circle[key] node; } } void removeNode(const string node) { for (int i 0; i virtualNodeNum; i) { string vnode node # to_string(i); size_t key hashFunc(vnode); circle.erase(key); } } string getNode(const string object) { if (circle.empty()) return ; size_t key hashFunc(object); auto it circle.lower_bound(key); if (it circle.end()) { it circle.begin(); } return it-second; } };6. 算法优化技巧6.1 位运算优化在算法竞赛和系统底层开发中位运算能极大提升性能。以下是几个常见技巧判断奇偶x 1交换两数a ^ b; b ^ a; a ^ b;取绝对值(x ^ (x 31)) - (x 31)判断2的幂x 0 (x (x - 1)) 06.2 记忆化搜索将递归算法的中间结果缓存避免重复计算是动态规划的另一种实现方式。unordered_mapint, int memo; int fibonacci(int n) { if (n 1) return n; if (memo.count(n)) return memo[n]; return memo[n] fibonacci(n - 1) fibonacci(n - 2); }7. 面试实战建议白板编码先在纸上写出伪代码理清思路再开始编码测试用例至少准备3组测试数据正常、边界、异常情况复杂度分析主动说明时间和空间复杂度展示算法思维代码风格良好的变量命名和适当的注释会加分沟通交流边写边解释思路遇到问题及时沟通8. 推荐练习平台LeetCode按企业分类刷题牛客网国内大厂真题Codeforces锻炼快速编码能力HackerRank系统设计题目较多9. 延伸学习资料《算法导论》- 经典算法教材《编程珠玑》- 算法思维训练《STL源码剖析》- 理解C标准库实现《深入理解计算机系统》- 底层原理10. 常见问题解答Q如何处理面试中没见过的题目 A先确认问题边界分解为已知的子问题尝试从暴力解法开始优化Q算法题做不出来怎么办 A展示思考过程比直接放弃好可以讨论可能的解决方向Q如何评估算法好坏 A从时间复杂度、空间复杂度、代码可读性、可维护性多维度评估在实际面试中我发现很多候选人虽然能写出算法但对时间复杂度的分析不够准确。建议在平时练习时对每道题都进行详细的时间复杂度分析养成习惯。例如对于嵌套循环不要简单地说O(n²)而要明确内层循环的迭代次数与n的关系。
返回列表