
用友2017秋招笔试题二这份卷子我刷完之后最大的感受是它不像BAT那样绕来绕去考智商而是很务实——Java基础、数据库、数据结构、基础算法每一道题都在问你“基本功扎不扎实”。做企业级软件的公司笔试题确实是这个风格。今天把这套题的核心考点、做题思路、踩坑点完整复盘一遍希望能给正在准备秋招的同学省点事。1. 用友秋招笔试题的整体画像与备考思路1.1 从用友的产品线反推考点看用友的笔试题之前得先知道这家公司是做什么的。用友做ERP、财务软件、人力管理软件起家B端企业服务是主业客户是各大中型企业。这类公司招技术岗产品特点决定了他们关心什么后端开发为主Java技术栈偏重因为大型企业应用离不开Java生态。数据库是命根子企业软件几十万张表、几千万行数据是常态SQL写不好没法干活。系统稳定性要求高财务数据出个差池后果严重所以考察的数据结构、算法题都偏向“稳”而不是“炫”。业务流程复杂笔试里经常出现带有业务味道的逻辑题比如单据状态流转、多层审批、金额分摊计算。理解了这几点再看2017秋招笔试题二的题目结构就会发现它考察的核心维度其实很集中数据结构与算法约占一半Java和数据库知识约占三成剩下的是逻辑思维和工程常识。1.2 为什么2017年的题目现在仍然值得刷我知道很多人看到“2017年”就有种“这都多老的题了”的错觉。但说实话校招笔试的考点刚需程度远超你想象Java集合类底层原理、HashMap的扩容机制、ArrayList和LinkedList的适用场景这些问法在当年的卷子上出现过现在的笔试题照样出现。数据库索引失效、SQL执行顺序、事务隔离级别这些知识点不会因为年份而改变。算法题的核心考点是链表、二叉树、字符串处理、动态规划入门这几乎是所有企业笔试的标配。所以刷这套题的目的不是“押中真题”而是通过一套有代表性的题目把企业笔试里最容易出现的知识点体系过一遍。用一套题作为提纲去展开复习你薄弱的部分这才是它的正确用法。1.3 备考时应该采取的复习策略说下我当时刷这套题的策略三个步骤第一遍整卷限时模拟严格按照考试时间来做不翻资料做完对答案。这样做是为了了解自己的定位哪些题一看就有思路哪些题完全没有头绪。第二遍按知识点分类整理错题。我会把错题分为数据结构和算法一组、Java基础一组、数据库一组每组再写出对应的复习资料章节和练习题方便后面针对性地补。第三遍专项突破薄弱点。哪里错得多就去找对应的专题练习大量刷直到看到同类题能形成条件反射。这个流程走完我大概花了两周时间。两周后的状态是再做一套同类型的卷子时间能提前十分钟完成正确率明显提升。更重要的是面试时被问到相关知识点我能很有底气地把“为什么”讲清楚而不只是背答案。2. 逐类拆解笔试核心考点数据结构、算法思维、Java与数据库2.1 数据结构不是背定义而是会比较和选型用友这套笔试题里数据结构相关的题目占比很高但考察方式不是“请写出二叉树遍历的递归实现”这种送分题而是更偏向于理解和选型。典型的考法有这么几类让你比较ArrayList和LinkedList在指定操作下的效率差异。比如在列表头部反复插入元素谁更快很多人凭感觉选了LinkedList但如果在ArrayList上做头插虽然要移动元素但内存连续带来的缓存命中率优势在小数据量下反而明显。要选对得搞清楚二者底层的存储结构和JDK版本优化。给你一个业务场景让你选最合适的数据结构。比如“需要频繁按照key查找对象且要求线程安全”HashMap加锁和ConcurrentHashMap怎么选这已经不是单纯考数据结构了还考并发基础。HashMap的put过程描述。从hash计算、寻址到put到数组或链表/红黑树再到扩容条件每一步细节都要能讲清楚这是Java岗笔试的经典题型。准备这块时我建议不要死记“ArrayList查快增删慢”这种结论而是去理解它背后的原理数组的内存连续性和链表的指针离散性决定了它们的缓存友好度不同扩容策略不同遍历方式的底层实现也不同。理解了原理题目怎么变你都能应对。2.2 算法思维边界条件和状态转移是分水岭算法题部分用友的难度定位比较实在——不搞冷门竞赛题重点考察基础算法的熟练度和思维的严密性。从题目类型来看高频出现的有字符串处理类反转字符串、统计字符频率、判断回文、子串匹配等。这类题看似简单但考察了char数组操作、String和StringBuilder的选择、以及各种边界条件的处理能力。链表操作类反转链表、合并两个有序链表、判断链表是否有环。这些题在LeetCode上是Easy或者Medium难度但笔试中出现频率极高。用友这种企业软件公司笔试考链表不看你的奇技淫巧就看你代码写得干不干净。简单的动态规划入门题比如爬楼梯、最大子数组和、编辑距离的朴素版本。重点不是把状态转移方程背下来而是需要你解释清楚为什么dp数组要这样定义、初始值为什么是这个、转移方程为什么成立。我还记得当时卷子上有一道很典型的动态规划题解题的关键一步在于把“每一步的状态只依赖前一步”这个特征识别出来。如果能看出这个结构即使你没专门学过DP也能用暴力递归加缓存的方式来解能拿大部分分。算法题准备上我的经验是搞懂每一道做过的题的时间复杂度和空间复杂度。每题都要会至少一种暴力解法和一种优化解法。边界条件像空输入、单元素输入、全相同元素都得单独考虑一遍。2.3 Java基础集合是重头戏JVM也不是可选项用友的笔试题里Java基础部分占有相当比重毕竟这是企业级开发的主力语言。集合类相关题目的高频程度不用多说另外还会涉及面向对象三大特性的实际应用场景比如多态在业务代码里的表现方式。异常处理机制 checked exception和unchecked exception的区别以及什么场景下该用哪种。泛型的类型擦除问题以及为什么Java的泛型设计成运行时擦除。JVM的基础概念主要是内存分区、GC收集器、类加载顺序。特别是JVM这一块很多人准备校招时容易轻视它总觉得“这是面试官才会问深的东西”。但实际上笔试里就有JVM的基础选择题比如“下面哪个区域不会发生OutOfMemoryError”“G1和CMS的区别”这类。你在笔试里遇到如果没复习过只能凭感觉蒙。Java基础的复习我建议以源码阅读为核心。深入看ArrayList、HashMap、ConcurrentHashMap的源码实现把这几个类的源码吃透你会发现好多笔试题都像是从源码里直接挖出来的。再看一遍《深入理解Java虚拟机》的内存管理部分配合一些八股文的背诵应对笔试就足够扎实了。2.4 数据库与SQL企业级开发的硬通货数据库题目是用友笔试的重头戏之一这和公司基因是直接挂钩的。ERP系统里最频繁的操作不是复杂算法而是从十几张关联表里查出正确的数据或者批量更新几百条受影响的单据数据。笔试题里常见的数据库考法包括手写SQL查询一般会涉及多表连接、分组统计、子查询和去重。索引相关概念比如什么时候索引会失效、联合索引的最左前缀原则、覆盖索引是什么意思。事务特性和隔离级别考的是脏读、不可重复读、幻读的区别以及InnoDB在可重复读级别下如何通过MVCC解决不可重复读。数据库设计题可能会给出一个小型需求让你设计表结构考察主键选择、字段类型选择和索引设计的合理性。对于手写SQL的部分套路上来来回回就那几个LEFT JOIN注意NULL值处理、GROUP BY分组后想筛选用HAVING不用WHERE、要排重先考虑DISTINCT能不能解决问题、子查询能不能改写成JOIN往往能提升性能。这些点练熟以后SQL题基本不会丢分。数据库设计的题目我踩过的一个教训是——不要为了省事把所有字段塞到一张表里。看起来简单了实际上在查询复杂度和后续扩展性上都会吃亏。正确做法是先根据实体关系拆分表再根据查询场景设计冗余字段和索引。3. 典型题目的实操复盘链表、动态规划与字符串处理这一章我把当年刷题时遇到的典型题目重新梳理一遍不光讲答案更注重解题思路的推导过程因为思路本身的通用性远大于一道题的正确解法。3.1 链表题反转链表的两种实现与现场推导链表题几乎是我国内大厂笔试的保留节目用友也考了。其中的反转链表题目非常有代表性。先说我的第一直觉最常见的迭代写法。维护两个指针prev初始为nullcurr从head开始走每走一步就把当前节点的next指向prev然后prev和curr各前进一步。最后返回prev就是反转后的头节点。这题只要纸上写过两次基本不会出错。迭代法的关键点是你要在改变curr.next之前先把curr.next的原始值保存下来否则链表从中间断开就找不回后续节点了。这个坑是初学者最容易踩的代码跑起来不是NullPointerException就是链表变成环。然后是递归实现递归实现写起来很简洁但是很容易写错public ListNode reverseList(ListNode head) { if (head null || head.next null) { return head; } ListNode newHead reverseList(head.next); head.next.next head; head.next null; return newHead; }递归法的核心逻辑是先把当前节点之后的链表反转拿到新的头节点然后把当前节点的下一个节点的next指向当前节点再把当前节点的next置空。理解的关键在于从宏观上信任递归函数“能够完成它的职责”。我当时笔试时遇到的是变体K个一组反转链表。这道题就没上面那道那么简单了需要先写一个辅助函数反转区间再在主函数里分块处理。我当时先用了最稳妥的办法先遍历链表确认满足K个一组的分组情况再逐组反转最后把各组串起来。虽然代码写得多一点但逻辑清晰不容易出错。笔试场景下先把功能做对再考虑优化这是最稳妥的策略。3.2 动态规划题从暴力递归到dp表的推导过程用友这套笔试题里的动态规划题目难度设置比较合理属于“看一眼知道是DP但状态定义需要动动脑”的程度。我当时遇到的一道典型题是“最大子数组和”。这题的暴力解法很容易想到双层循环枚举所有子数组逐个求和找最大值时间复杂度O(n^2)。在笔试有限的样例数据下这写法可能能过但不够优雅。动态规划的推导过程是这样的定义一个dp[i]表示以第i个元素结尾的子数组的最大和那么dp[i]只有两种来源要么把nums[i]拼接到前面的子数组上即dp[i-1] nums[i]要么不拼从nums[i]重新开始一个新的子数组即nums[i]。所以转移方程是dp[i] max(dp[i-1] nums[i], nums[i])。最终的答案就是dp数组里的最大值。这个状态定义和转移方程推导清楚以后代码写出来非常简单public int maxSubArray(int[] nums) { int[] dp new int[nums.length]; dp[0] nums[0]; int result dp[0]; for (int i 1; i nums.length; i) { dp[i] Math.max(dp[i - 1] nums[i], nums[i]); result Math.max(result, dp[i]); } return result; }一开始我对dp[i-1] nums[i]和nums[i]取最大值这个操作不太理解后来用具体的数组走了一遍才明白。比如数组[-2, 1, -3, 4, -1, 2, 1, -5, 4]当i等于3时nums[3]是4dp[2]是负数那dp[2] nums[3]反而比nums[3]小说明前面的累加已经拖后腿了不如干脆从4重新开始。这就是“以第i个元素结尾”这种状态定义的精妙之处它把问题拆成若干个以不同元素结尾的子问题而子问题之间天然有依赖关系只需要找到正确的转移方式。笔试中做DP题我总结了一套固定流程先想最暴力的解法看看有没有重叠子问题。有重叠子问题就尝试定义dp数组的含义一般是从“以什么什么结尾”或“前几个元素怎么怎么样”这两个角度入手。写转移方程时把“当前状态可能由哪些之前状态转移而来”列全别漏掉情况。初始化要单独拿出来想清楚dp[0]或dp[0][0]的值是什么边界情况是什么。这套流程走下来就算没解出最优解也能通过写暴力和部分优化拿不少分。3.3 字符串题判断回文与子串处理的若干坑字符串处理是笔试中容易“丢分丢得稀里糊涂”的部分因为大部分字符串题看起来简单但实现起来会导致各种隐蔽的错误。最常见的回文判断题最直白的解法是双指针法一头一尾向中间逼近public boolean isPalindrome(String s) { int left 0, right s.length() - 1; while (left right) { if (s.charAt(left) ! s.charAt(right)) { return false; } left; right--; } return true; }注意边界条件空字符串和单字符字符串都算回文。指针移动时要注意“先比较后移动”否则会漏判。如果题目再升级一层让你判断“忽略空格和标点只看字母数字是否回文”那就要在循环里两个while跳过非目标的字符。我当时在这道题上吃过亏跳过字符时没有判断指针越界导致遇到全标点字符串时下标飞出去了。正确写法是要在while循环里把left right条件一起带上。字符串处理的另一大考点是子串匹配朴素做法是长度匹配再逐位比较而KMP算法虽然高效但笔试里遇到的概率不高。我自己的建议是如果对KMP不熟笔试里用朴素匹配加上剪枝就行大多数测试用例数据量都不会太大过了就行。3.4 一场完整笔试的做题现场模拟说一套完整的模拟过程。当时我做这套用友2017秋招笔试题二时先快速扫了一遍所有题目把简单题标记为“第一优先级”中等难度标记为“第二优先级”完全没有思路的标记为“最后攻克”。第一优先级是选择题和简单SQL题先快速做完确保基础分拿到手。这些题目量大但耗时少卡住超过两分钟就先跳过。第二优先级是算法题。我一般来说先做自己最擅长的类型我链表题熟练度最高所以先做链表题然后是字符串题这类题思路清晰实现也快最后剩下的是DP题留了比较多的时间来想状态转移。整个做题过程中我习惯在草稿纸上写一写伪代码和核心边界条件。这对后面写代码非常有帮助因为笔试环境里没有调试器草稿纸就是你的“大脑外存”。有些同学一上来就开始写代码写到一半发现逻辑有缺陷又要推翻重来非常浪费时间。做完所有题目后如果还剩时间重点检查两类题一类是手写SQL检查表连接条件是否漏了、聚合函数分组是否正确另一类是算法题的边界情况用空输入、单元素输入和极端长度输入代入跑一遍。这个过程能拦住不少“看起来正确实际跑起来崩溃”的问题。4. 做题顺序、时间分配与笔试平台操作细节4.1 时间分配策略先拿保底分再啃硬骨头一套笔试通常是一个半到两个小时题量在20到30题之间包含选择、填空、SQL和编程题。时间分配不合理的同学很容易出现一种情况前面选择题纠结太久后面编程题连看题的时间都不够。我的建议是选择题每道最多1分钟连做带蒙不要恋战。不是所有选择题都值得当作知识点去推理有些纯背诵类的题会就是会不会就蒙一个走人。SQL题每道控制在3分钟以内如果5分钟还没写出来先跳过。编程题每道留足10到15分钟。先把思路写清楚再写代码。如果总时间剩余不多优先保证能完整跑通一道题而不是三题都写了一半。这套策略的核心逻辑是把所有确定性得分都拿到手再争取不确定性得分。选择填空题是确定性得分只要落笔就有50%以上的概率蒙对编程题是不确定性得分写一半在评委眼里就是“不可运行”。4.2 笔试平台的环境坑与应对办法在校招笔试平台上写代码和你平时在IDE里写代码完全是两个世界。主要有以下几个坑没有自动补全。平时写代码靠IDE提示拼写到了笔试环境类名拼错、方法名拼错、括号不匹配这类问题非常致命。所以平时练习就要有意识地默写代码不依赖IDE的自动补全功能。没有调试器。运行报错只能靠肉眼和print而且很多平台print是会被禁用的。解决方法是写代码时头脑里模拟一遍执行过程对变量变化有预判。输入输出格式严格。有些题目要求“输出结果用空格分隔”或“换行输出”少一个空格都可能判错。刷题时注意阅读平台给出的示例尤其是输出样例末尾是否有空格或换行。有的平台是分“提交代码”和“在线评测”两个环节的提交后不会立刻告诉你结果。这时候你更要在提交前做足自查别指望后台会提示你哪错了。4.3 笔试后的复盘方法把一套题的价值榨干笔试最大的价值不在考场而在考后复盘。我每次笔试完都会在当天趁热整理一份复盘文档格式很简单每道错题对应哪个知识点。做错的原因是什么是知识点没掌握还是审题不仔细还是时间分配导致的失误。这个知识点后续该用什么资料复习、找哪些题巩固。这次考试暴露出的时间分配问题怎么调整。然后我会统计错题的知识点分布如果发现某个知识点反复出现说明这是高频考点也是我的薄弱环节。接下来一周的复习重心就放在这里。这个方法比盲目刷题高效得多因为你花时间瞄准的是真实的失分点。复盘时有一个容易忽略的细节不要只看“这题是选A还是选B”还要看选对的那些题是不是真的会还是蒙的。如果蒙对的题目对应的知识点没有掌握也要认真补上否则下次换个角度再考你还是不会。5. 常见失分点与避坑清单实录5.1 高频失分点前人踩过的坑你就别踩了我在刷题和复盘过程中发现了几个出现频率极高、但完全可以避免的失分点单独列出来提醒大家空指针异常。Java编程题里最常见的崩溃原因调用了null对象的方法或字段。拿到链表题、树题第一件事就是判断输入是否为null。数组越界。遍历数组时循环条件写错导致下标溢出。建议统一用i length而不是i length - 1的写法虽然效果一样但更容易避免越界。整数溢出。求和或乘方时没有考虑到int的范围结果爆掉变成负数直接判错。涉及大数运算优先用long。忽略题目中的特殊约定。比如题目说“假设输入非空”那你就不用写空判断题目说“结果对1000000007取模”那就是暗示答案可能很大。手写SQL时忘了条件。多表关联时漏了JOIN的ON条件或者只写了WHERE没写GROUP BY就用了聚合函数这些都是低级错误练习时就要养成检查的习惯。5.2 避坑清单笔试前快速过一遍的必查项目每次笔试前我会在脑子里过一遍这个清单编程题先确认输入和输出的格式看示例别写完了才发现格式不对。整个解法的时间复杂度是不是已经能在题目限制内跑完数据量最大的情况。链表、树、图这类结构是否处理了空输入、单节点、环等情况。代码里是否用了未导入的包或类笔试环境不是全自动导包的。Java代码中是否用到了中文标点符号比如全角括号或全角分号编译器可不认识这些。数据库题中JOIN的方向是不是弄反了LEFT JOIN和INNER JOIN别搞混。选择题里凡是有“不正确”“不属于”“错误”这类字眼的在“不”字上画个圈再答。这个清单我每次考试前都会看一遍节省了非常多的时间。复习的时候感觉知识点都掌握了到了考场才发现问题是出在“题干里有个‘不’字没看见”这真的是最冤的丢分方式。5.3 心态调节与临场发挥的个人经验最后聊一聊心态层面的事。校招笔试本质上是一场限时压力下的基础能力测试紧张是正常的但要注意几个容易导致发挥失常的情况。第一个是“被一道题困住就走不出来了”。一套卷子是一个整体一道选择题卡住五分钟看起来只是损失五分钟实际上你的注意力会被牵制后面的题做起来效率会下降。遇到不会的题先标个记号跳过去回头再来这是最理性的选择。第二个是“看到别人交卷就慌了”。笔试一般不会因为你提前交卷加分反而是你自己因为匆忙交卷漏做了好几道题。稳扎稳打做完自己会做的再考虑交卷的事。别人的节奏与你无关。第三个是“只刷题不总结”。只做题不复盘做一百道和做十道没有本质区别。每一套题做完后梳理出知识点图谱找到自己的薄弱环节比多刷一套卷子更有价值。我在准备校招的过程中完整的复盘文档写了将近一百页回头翻看的时候那些曾经做错的知识点全都牢牢印在脑子里了。说实话一套2017年的秋招笔试题放到现在来看难度不算高但它的知识点覆盖非常好很适合用来检查自己的基础是否扎实。如果你能用这套题做到“每道题都能说出考什么、为什么这么考、下次遇到同类题怎么做”那么你应对大部分企业级软件公司的校招笔试都不会有问题。