广联达2018校招笔试复盘:算法与计算机基础全解析
1. 为什么一份七年前的笔试题现在读来依然有用先说说我为什么想写这篇内容。前阵子翻电脑里的老文件夹找出一份当年参加广联达2018校招开发工程师笔试时的记录和草稿。那会儿临近毕业简历投了一堆笔试也参加了不少广联达这场算是给我印象比较深的一场。倒不是因为它有多难而是它的考察范围非常典型——“数据结构与算法 语言基础 计算机基础四件套 少量业务场景题”几乎就是国内软件开发岗校招笔试的标准样本。回过头来看广联达的笔试难度定位很明确不追求极致的难题压轴而是强调基础功扎实。这和公司本身的业务形态有关。广联达做的是建筑行业信息化覆盖造价、施工、BIM、数字建造这些方向软件产品线既包括桌面端工具也包括云端平台和移动端应用。开发岗位技术栈偏C、C#、Java需要工程师既懂底层又要有工程化意识。所以笔试不会像部分互联网大厂那样上来就扔一道大模拟或冷门图论更多是考察你在学校积累的核心基础。这篇文章我会把当年那场笔试从题型结构到具体题目复盘一遍重点分析编程题的完整解题思路、选择题里的高频失分点以及整个备考和应试的时间安排策略。无论你是正在准备校招的应届生还是想跳槽但需要重新捡起笔试能力的工程师都可以参考一下。即便你不是面建筑信息化方向这份卷子的考察逻辑也基本覆盖了大部分中大型公司开发岗笔试的底层要求。2. 题型大盘点这份卷子究竟在考什么先看一下整体结构。2018年那场笔试是在线上完成的总时长120分钟满分100分。题型分布我记得大致是题型题量分值占比考察内容选择题20题左右约40分C/Java语言基础、操作系统、计算机网络、数据库、逻辑题编程题3题约45分字符串处理、动态规划、图论/拓扑排序、模拟题简答/场景设计题1-2题约15分系统设计思路、异常处理、业务场景分析选择题部分覆盖范围比较广。我记得卷子里有几道典型的C题考查的是类型转换、运算符优先级、析构函数调用顺序这类细节Java岗位则更倾向考集合类的底层原理、多线程和异常机制。还有几道操作系统题涉及进程线程区别、死锁的必要条件、虚拟内存换页策略网络部分的题目主要集中在TCP三次握手、四次挥手状态变化以及HTTP状态码的含义上。数据库选择题基本是事务特性和索引结构。编程题难度递进比较明显。第一道是典型的字符串/数组处理题属于“热身题”不涉及复杂算法第二道是动态规划正儿八经地考状态定义和转移方程第三道稍微特殊一些是带业务背景的图论题——在一堆工序之间给出依赖关系要求输出一种可行的执行顺序。这种题目在互联网公司里也很常见但放在建筑信息化公司的卷子里显得特别应景因为施工现场的工序排期本质上就是这种依赖调度问题。简答题/设计题不是每个岗位都有部分岗位会出我记得是类似“如果要设计一个项目管理系统的任务分配模块你会怎么设计”这种。这类题目没有标准答案重点考察的是你有没有系统思维能不能把需求拆成模块考虑数据模型、接口设计和异常处理。这类题的核心其实是考察分析能力而非记忆能力。整体来看这份卷子没有特别刁钻的题但对“全面性”的要求很高。很多同学平时刷题只盯着LeetCode上的热门题结果选择题里栽了跟头。反过来也有同学基础概念背得滚瓜烂熟但编程题因为不熟悉在线笔试环境而没写完。这两类情况在这份卷子里都会被精准筛选出来。3. 编程题拆解从签到题到压轴题的完整解题复盘3.1 字符串处理题送分题里的边界陷阱编程题第一道通常是字符串处理这类题目的定位就是“先让你写出一道能通过的题”用来区分“完全不会写代码”和“能写出代码”的人。我记得当年的题目要求大概是给定一个字符串找出其中不含重复字符的最长子串长度。这个题如果用暴力的方式做就是从每个位置出发尝试往后扩展同时用哈希表记录字符是否重复。时间复杂度是O(n²)在字符串长度不大时也能通过但如果测试数据给到10的5次方以上就会挂掉。正确的做法是滑动窗口。class Solution { public: int lengthOfLongestSubstring(std::string s) { std::vectorint pos(256, -1); int left 0; int maxLen 0; for (int i 0; i s.length(); i) { if (pos[s[i]] left) { left pos[s[i]] 1; } pos[s[i]] i; maxLen std::max(maxLen, i - left 1); } return maxLen; } };这段代码核心思路是维护一个窗口窗口内部保证没有重复字符。i作为右边界不断向右扩展当发现当前字符上一次出现的位置在窗口内即pos[s[i]] left说明有重复直接把left跳到上一次出现位置的右边。pos数组记录了每个字符最近一次出现的位置所以不需要额外的哈希表用长度为256的int数组就够了。这里有几个容易踩的细节。第一left的更新条件必须是而非否则当字符在窗口内出现时会漏判。第二pos数组初始化为-1表示字符未出现过这个初值很重要如果初始化为0下标为0的字符就会出现误判。第三边界情况空字符串返回0单字符串返回1。我当时这个题写得很顺因为平时练得多大概五分钟就AC了。但注意这种“送分题”最大的风险不是不会做而是因为粗心在边界条件上挂掉。很多在线笔试系统不会告诉你到底哪组数据错了所以一遍写对的能力很重要。3.2 动态规划题背包类问题的状态定义与遍历顺序第二道编程题我记得是背包问题的变种。大概是这样的场景一个施工项目的预算是M有N种材料可以选择每种材料有重量成本w[i]和价值v[i]并且每种材料最多只能选一次问在预算范围内能获得的最大总价值是多少。这就是经典的01背包问题。背包问题的核心在于状态定义。我们定义dp[j]表示总重量或者总预算恰好为不超过j时能获得的最大价值。然后对每个物品i用下面的转移方程更新dp[j] max(dp[j], dp[j - w[i]] v[i])关键是内层循环需要从M往w[i]方向倒序遍历。为什么要倒序因为正序遍历时同一个物品可能被选中多次这就变成了完全背包问题。倒序遍历可以确保dp[j - w[i]]是上一轮即还未考虑当前物品的值从而保证每个物品只被选一次。#include iostream #include vector #include algorithm int main() { int N, M; std::cin N M; std::vectorint w(N), v(N); for (int i 0; i N; i) { std::cin w[i] v[i]; } std::vectorint dp(M 1, 0); for (int i 0; i N; i) { for (int j M; j w[i]; --j) { dp[j] std::max(dp[j], dp[j - w[i]] v[i]); } } std::cout dp[M] std::endl; return 0; }这段代码的时间复杂度是O(NM)空间复杂度是O(M)。如果完全按朴素二维数组写法空间复杂度是O(NM)在M较大的时候可能会超内存所以滚动数组压缩是必须掌握的技能。关于这道题我在考场上还犯过一个低级错误就是把N和M的输入顺序搞反了。题目里先输入N后输入M我一开始没仔细看结果输出一直不对。后来冷静下来重新读题才发现。这个教训很实在动笔之前先把题目输入输出格式读完不要着急写代码。背包问题在笔试中出镜率极高但出题人通常不会直接说“这是背包问题”而是套一层业务外壳比如这个题目包装成“预算和材料选择”。识别出题目的算法本质是解题的第一步。3.3 与业务挂钩的图论题施工工序排期与拓扑排序第三道题我记得比较清楚因为它明显带有广联达的业务色彩。题目大意是一个工程项目包含N道工序工序之间存在依赖关系比如“浇筑混凝土”必须等“绑扎钢筋”完成之后才能开始。给定M条依赖关系要求输出一种可行的工序执行顺序。这道题的本质就是拓扑排序。拓扑排序适用于有向无环图核心思路是统计每个节点的入度把所有入度为0的节点放入队列依次从队列取出节点输出它并把依赖它而指向的邻居节点入度减1如果某个邻居入度变为0加入队列如果最后输出的节点数小于N说明图中存在环无法完成全部工序。#include iostream #include vector #include queue int main() { int N, M; std::cin N M; std::vectorint indegree(N 1, 0); std::vectorstd::vectorint graph(N 1); for (int i 0; i M; i) { int a, b; std::cin a b; graph[a].push_back(b); indegree[b]; } std::queueint q; for (int i 1; i N; i) { if (indegree[i] 0) q.push(i); } std::vectorint order; while (!q.empty()) { int cur q.front(); q.pop(); order.push_back(cur); for (int nxt : graph[cur]) { indegree[nxt]--; if (indegree[nxt] 0) q.push(nxt); } } if (order.size() ! N) { std::cout 存在循环依赖无法安排工序 std::endl; } else { for (int i 0; i order.size(); i) { std::cout order[i] (i order.size() - 1 ? \n : ); } } return 0; }注意这道题的进阶考点是两个如果题目要求字典序最小的拓扑序列就需要把queue换成priority_queue每次取出编号最小的入度为0节点如果不只要求一种可行顺序而是问有多少种方案那就是DP 状态压缩难度会直接翻倍。广联达那道题当时只要求任意一种可行顺序所以用队列就够了但考完之后我在牛客网上看到有人讨论如果要求字典序最小该怎么改这个思路很值得掌握。这道题让我感觉广联达的笔试不是纯算法竞赛它会把技术问题和业务场景结合起来让你觉得“这个题目放在施工管理软件里真的有实际用途”。建筑行业里的工程施工进度编排、材料供应计划、人力调配本质上都是资源约束下的排程问题。笔试出这样的题说明公司确实在寻找能理解业务逻辑的工程师。4. 选择题里的魔鬼细节语言基础的知识点隐性考察编程题只要能力够就能拿分但选择题往往是拉开分数差距的地方。因为这些题考的是“你知道这个知识点但你是否知道得很准确”。我在这里栽过几次跟头印象特别深。4.1 C里构造函数和析构函数的调用顺序有一道题大概是给了三个类A、B、C其中A继承B同时A内部有一个C类型的成员对象。问题是构造A时构造函数和析构函数的调用顺序是什么正确答案是先调用基类B的构造函数再调用成员对象C的构造函数最后调用A自身的构造函数析构顺序完全相反先A自身再成员对象C最后基类B。我当时就差在了成员对象和基类的顺序上。实际编译验证一下就知道基类优先生命周期更长成员对象次之类自身最后。这个顺序是C对象生命周期的基础逻辑如果连这个顺序都搞错后续涉及内存管理的题目基本就废了。4.2 Java里HashMap的底层结构和扩容条件Java方向的技术岗候选人会碰到HashMap相关的题目。比如HashMap的初始容量是多少加载因子是多少什么时候触发扩容答案是初始容量16加载因子0.75当元素个数超过当前容量 * 加载因子即16*0.7512时哈希表会扩容为原来的两倍。这些数值本身是经验值0.75是时间成本和空间成本的折中。Java 8之后当一个桶位的链表长度超过8且数组长度不小于64时链表会转成红黑树把查询时间复杂度从O(n)降到O(log n)。这些细节如果只靠背答案换个问法就容易懵比如“HashMap的key可以为null吗”答案是允许一个null key并且它总是被放在table[0]位置此时要经过特殊处理。这类题目考的就是你对底层结构的理解是否深入、平时的积累是否扎实。4.3 字符串比较永远考不腻的经典题C里char*的比较和C string的比较规则不一样。char* p1 p2比较的是指针地址而不是内容string直接用比较内容。Java里比较引用值比较需要调equals。有一个经典陷阱new String(abc) abc返回false但abc abc返回true因为字面量abc来自常量池。这类题看起来简单但做错的人大把原因就是语言的这些“约定俗成”远谈不上直觉。4.4 面试官想要什么我复盘这些题的感想是语言基础的题目不是为了刁难人而是为了筛选“真正写过代码、踩过坑”的人。如果一个候选人连自己主语言的字符串比较规则都说不清楚很难让面试官相信他能写出稳定的工程代码。5. 操作系统、网络与数据库非算法题怎么拿到稳定分整张卷子的非算法题部分操作系统、计算机网络和数据库占了相当比例。这部分比算法题更适合系统性复习因为考点相对固定理解原理后就不容易丢分。5.1 操作系统题的两个高频块操作系统题目中进程线程和死锁是两大块。进程是资源分配的最小单位线程是CPU调度的最小单位同一个进程内的线程共享地址空间而进程之间是相互隔离的。为什么多线程比多进程更“轻”因为创建进程时需要分配独立的内存空间而线程只需要创建栈和寄存器上下文。这里容易考一道题多线程之间共享什么不共享什么共享的是堆、全局变量、静态变量、文件描述符不共享的是栈和寄存器。这个点答清楚说明你对并发模型有真实理解。死锁的必要条件有四个互斥、持有并等待、不可剥夺、循环等待。要破坏死锁只需要破坏其中一个条件即可。常见的死锁预防策略包括一次性申请所有资源破坏持有并等待、资源编号按序申请破坏循环等待、允许抢占破坏不可剥夺。经典哲学家就餐问题就是典型的死锁场景笔试里可能会出现变形比如“两个线程各自持有一个锁然后互相等待对方的锁”这种情况考察你能不能识别出deadlock并给出解决方案。5.2 网络题从握手到状态码TCP的三次握手和四次挥手几乎是必考。三次握手的作用是让通信双方确认对方的收发能力正常同时交换初始序列号。三次不能再少如果只用两次握手服务端无法确认客户端的接收能力是否正常也无法防止迟到的连接请求建立无效连接。四次挥手是因为TCP连接是全双工的因此每个方向的关闭都需要单独确认。HTTP状态码我整理一下容易混的2xx代表成功其中200表示OK201表示Created3xx代表重定向其中301是永久重定向302是临时重定向304是未修改常用于协商缓存4xx是客户端错误其中400是Bad Request401是未认证403是禁止访问404是资源不存在429是请求过多5xx是服务端错误500是内部错误502是网关错误503是服务不可用504是网关超时。当年选择题里就有一道“用户访问权限不足时应该返回哪个状态码”选项里有401和403正确答案取决于具体语义未登录通常是401已登录但无权限则是403。5.3 数据库事务特性与索引数据库题目基本集中在事务、索引、锁三个方面。事务的ACID四性原子性A、一致性C、隔离性I、持久性D。四个隔离级别读未提交、读已提交、可重复读、串行化对应不同的并发问题脏读、不可重复读、幻读。索引方面B树是数据库最常用的索引结构因为它是多路平衡搜索树树高很低磁盘IO次数少同时叶子节点通过链表连接非常适合范围查询。这里容易考的问题是“最左前缀原则”在一个联合索引(a, b, c)上查询条件只有b时无法用到索引因为联合索引的排列顺序是a优先。这个考点在笔试里出现频率很高如果不懂最左前缀原则基本上会白丢分。我当时备考数据库的策略比较简单先把《高性能MySQL》里关于索引和事务的章节过一遍再刷一遍常见的SQL笔试题基本就能覆盖大部分公司笔试的数据库考点。不一定需要把所有索引优化技巧都背下来但事务隔离级别和索引失效的常见场景必须完全掌握。6. 应试策略复盘120分钟怎么安排才能写完算法题和概念题都会做是一回事能在120分钟内把所有题做完并且保证正确率是另一回事。这套笔试我最后时间刚刚好复盘下来有几个策略很值得分享。6.1 时间分配大法我当时的时间安排是前40分钟做选择题中间60分钟做编程题最后20分钟检查。选择题里如果出现超过两分钟还拿不准的题目先标记跳过不要恋战。因为选择题每题分值一般不超过2分耗费八分钟在上面是得不偿失的。编程题分值高必须保证充足的时间。编程题的顺序按难度来第一道简单题必须在15分钟内完成并提交第二道中等题给25-30分钟第三道难题最多留15-20分钟。如果第三道实在没有思路先把手上的部分代码写好至少能拿到一些测试用例的分数。很多在线笔试平台按通过的测试用例比例给分空题倒是零分不如把暴力解法写上去。6.2 在线笔试环境下的“隐形陷阱”2018年的在线笔试平台和现在类似比如牛客网、赛码网都要自己处理输入输出。这里有一个很大很常见的坑本地IDE能跑通但是平台不认。原因通常是输入输出格式不对比如题目要求“每行输出一个结果”你却在同一行用空格分隔或者要求输出结束时没有换行。建议平时刷题就直接在牛客网或力扣的在线编辑器上练而不是只在本地IDE里跑通就算。另外一个坑是编译器的差异。有些平台默认C标准是C14有些是C17。如果你用C11的写法在C14环境没问题但用到了C17才有的特性比如std::filesystem就会编译失败。我当时在代码里尽量只写C98/11的基本语法避免高版本特性省得编译报错浪费宝贵的冷静时间。6.3 草稿纸的正确用法在线笔试允许使用草稿纸但很多人不会用。我建议拿到题目后第一件事不是在草稿纸上抄题目而是把每个编程题的核心思路先写出来。比如第二道背包题我会先写下“dp[j] max(dp[j], dp[j-w]v)内层倒序”确认无误后再上屏写代码。这样在写代码的过程中大脑不需要同时做“想算法”和“写代码”两件事出错率会显著下降。6.4 心态不追求满分追求会做的全对这套笔试卷子的满分是100分但录取线一般不会划到90分以上。我后来了解到的信息是笔试大概在60-70分以上就有机会进面试。所以不要因为一道题卡住就焦躁更应该把已经会做的题做到滴水不漏。笔试拼的是得分率不是拿到所有分数。7. 这些题目背后映射的广联达技术栈与人才培养倾向把这份笔试卷子放在广联达的业务背景下看会发现出题思路很符合公司的技术布局。7.1 桌面端产品强依赖C能力广联达的明星产品如土建算量软件、钢筋算量软件、BIM建模工具底层大量使用C进行几何计算、三维渲染、CAD内核开发。建筑模型动辄几百万个构件对这种软件来说性能和内存管理是重中之重。所以笔试卷子里C的指针、内存、虚函数、STL容器等基础题出现频率很高。如果你能答对“为什么vector扩容时迭代器会失效”这类问题会更容易获得面试官的好感。7.2 云端化转型背后的服务端技术需求广联达也在推进云化和平台化所以像Java、数据库、网络相关的考点并没有被忽视。结合BIM和项目协同企业的业务已经呈现出非常典型的SaaS服务模式很多应用也部署在云端。笔试里数据库事务和索引的题目对应的是云平台上的海量数据处理TCP和HTTP的题目对应的是客户端和云端服务长连接、短连接以及实时通信的设计。这些考点背后对应的是公司在工程管理协同平台、大数据造价分析等产品上的实际技术需要。7.3 场景题考察的是业务理解力在选择题或者可能出现的简答题中场景题占了相当的分量。2018年那会儿是建筑行业数字化开始加速的时期广联达需要的不只是一个“会写代码的人”还需要能理解施工流程、造价逻辑的工程师。比如施工工序排期的问题放到建筑企业里就是项目经理每天都在想的事。如果你能在面试时顺带提一句“这道题让我想到施工进度计划中的关键路径法”面试官大概率会眼前一亮。业务理解力是常规算法题考不出来的能力但恰恰是这类行业软件公司最看重的能力之一。我备考广联达笔试时有一份感触它不像互联网大厂那样海量刷题就能过关也不像国企那样考行测和英语而是很务实地把工程软件行业所需要的技术基础铺开考了一遍。认真准备这份试卷其实也是对计算机专业基础的一次全面梳理这在之后面试其他公司时同样受用。写在最后笔试之后的一点感悟参加过2018年广联达校招笔试并对技术面试做了充分准备之后我最大的体会是笔试真正拉开差距的不是会不会做难题而是能不能把能力范围内的题全部拿到分。后来我养成了一个习惯——每次在线笔试前用一张纸把每种题型的答题时间上限写清楚贴在显示器边上提醒自己。这个习惯让我在后续多次笔试和面试中受益很多。再分享一个实用小技巧刷动态规划题时不要只满足于把代码写对试着把状态转移方程用文字在注释里写一遍比如dp[j]代表“预算为j时能获得的最大价值”。这个动作可以在笔试时帮你快速找回思路而且万一代码有bug注释能帮你定位到底是状态定义错还是转移逻辑错。对于广联达这类建筑信息化企业的笔试题我的建议是把计算机基础的四门课撸扎实把最常见的三类算法题字符串、动态规划、图论练熟再留出时间了解一点行业业务逻辑你就能在笔试中拿到一个不错的分数。希望这份回顾对你准备校招笔试能有实实在在的帮助。

相关新闻

最新新闻

日新闻

周新闻

月新闻