C++机试题目解析:字符串压缩与矩阵旋转技巧
1. 项目概述C机试题目解析T76-T80最近在整理C机试题目时发现T76-T80这组题目特别适合用来检验基础语法和算法思维的掌握程度。这五道题涵盖了字符串处理、数学运算、数据结构应用等常见考点很多互联网公司的笔试都会出现类似题型。我把自己在解题过程中积累的经验和踩过的坑整理出来希望能帮助到正在准备机试的朋友们。提示本文所有代码示例均基于C17标准在VS Code GCC 9.4环境下测试通过。建议读者先自行尝试解题再看解析效果更佳。2. 题目详解与实现方案2.1 T76字符串压缩算法这道题要求实现类似aaabbbbcc→a3b4c2的字符串压缩功能。看似简单但有几个易错点需要特别注意string compressString(const string str) { if(str.empty()) return str; string result; char current str[0]; int count 1; for(size_t i 1; i str.size(); i) { if(str[i] current) { count; } else { result current to_string(count); current str[i]; count 1; } } result current to_string(count); return result.size() str.size() ? result : str; }实现要点处理空字符串的特殊情况使用size_t而非int避免符号比较警告最后需要再次追加最后一个字符的统计比较压缩前后长度决定返回值踩坑记录最初忘记处理空字符串导致段错误后来添加了首行检查。另外要注意数字转字符串要用to_string而非强制类型转换。2.2 T77矩阵旋转90度这道经典题目要求原地旋转N×N矩阵。关键在于找到元素旋转的规律void rotate(vectorvectorint matrix) { int n matrix.size(); // 先沿主对角线翻转 for(int i 0; i n; i) { for(int j i; j n; j) { swap(matrix[i][j], matrix[j][i]); } } // 再水平翻转 for(int i 0; i n; i) { reverse(matrix[i].begin(), matrix[i].end()); } }算法分析时间复杂度O(N²) 必须访问所有元素空间复杂度O(1) 原地操作替代方案也可以直接计算新位置 matrix[i][j] → matrix[j][n-1-i]2.3 T78二叉树层序遍历这道题考察树的BFS遍历需要记录每层的节点值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; }注意事项使用队列实现BFS时要先记录当前队列大小即该层节点数处理完一层后要及时将子节点入队空树情况需要特殊处理3. 进阶题目解析3.1 T79链表排序O(nlogn)要求对链表进行O(nlogn)排序最适合归并排序ListNode* sortList(ListNode* head) { if(!head || !head-next) return head; // 快慢指针找中点 ListNode *slow head, *fast head-next; while(fast fast-next) { slow slow-next; fast fast-next-next; } ListNode* mid slow-next; slow-next nullptr; // 切断链表 return merge(sortList(head), sortList(mid)); } ListNode* merge(ListNode* l1, ListNode* l2) { ListNode dummy(0); ListNode* tail dummy; while(l1 l2) { if(l1-val l2-val) { tail-next l1; l1 l1-next; } else { tail-next l2; l2 l2-next; } tail tail-next; } tail-next l1 ? l1 : l2; return dummy.next; }优化技巧使用dummy节点简化合并逻辑快慢指针找中点比计算长度更高效递归深度为logn栈空间复杂度为logn3.2 T80最小覆盖子串滑动窗口这道hard题目考察滑动窗口技巧string minWindow(string s, string t) { unordered_mapchar, int need, window; for(char c : t) need[c]; int left 0, right 0; int valid 0; int start 0, len INT_MAX; while(right s.size()) { char c s[right]; if(need.count(c)) { window[c]; if(window[c] need[c]) valid; } while(valid need.size()) { if(right - left len) { start left; len right - left; } char d s[left]; if(need.count(d)) { if(window[d] need[d]) valid--; window[d]--; } } } return len INT_MAX ? : s.substr(start, len); }关键点分析使用valid变量统计满足条件的字符数右指针扩展窗口左指针收缩窗口每次validneed.size()时更新最小窗口时间复杂度O(n)空间复杂度O(m)m为t的长度4. 机试通用技巧与调试方法4.1 常见问题排查指南在机试环境中常遇到以下问题及解决方案问题现象可能原因解决方案段错误空指针访问/数组越界添加边界条件检查超时算法复杂度高分析时间复杂度优化算法部分通过特殊case未处理补充边界测试用例编译错误环境差异确认编译器版本和标准4.2 调试技巧实录打印调试法在关键位置插入打印语句cout Debug: i i , j j endl;小数据测试构造简单测试用例手动验证// 测试用例 assert(compressString(aaabbb) a3b3);分步验证将复杂算法拆解为多个函数单独测试内存检查使用valgrind检测内存泄漏本地环境valgrind --leak-checkfull ./your_program5. 性能优化与代码规范5.1 常用优化手段输入输出加速ios::sync_with_stdio(false); cin.tie(nullptr);预分配内存vectorint v; v.reserve(1000); // 避免频繁扩容减少拷贝使用引用传递大对象void process(const vectorint nums); // 而非vectorint nums5.2 代码规范建议命名风格统一变量小写类名大写适当添加注释解释复杂逻辑函数不超过50行保持单一职责避免使用全局变量合理使用const修饰符6. 扩展学习资源6.1 推荐练习平台LeetCode按标签筛选题目字符串、树、图等Codeforces参加定期比赛锻炼编码速度牛客网各大公司真题题库6.2 经典参考书籍《C Primer》全面掌握语言特性《算法导论》深入理解算法原理《剑指Offer》针对性准备面试题在实际刷题过程中建议先独立思考20分钟再查看答案每道题至少实现2-3种解法。对于错题要建立错题本记录错误原因和正确思路。我个人的经验是坚持每天3道中等难度题目两个月后机试通过率能提升80%以上。