一、企业概况
1.1公司简介
华为技术有限公司成立于 1987 年,总部位于深圳,业务覆盖运营商网络、企业业务、终端、云计算与数字能源,是全球领先的 ICT 基础设施与智能终端提供商。OD(Outsourcing Dispacth)是华为与人力服务商合作的外包用工模式,由服务商签约、在华为项目组内工作,考核方式与自有员工接近,但合同主体与晋升通道不同。OD 的 Java 岗位一般落在业务系统开发与内部平台建设上。
| 成立时间 | 1987 年 |
| 总部 | 深圳 |
| 主营业务 | ICT 基础设施、智能终端、云计算与数字能源 |
| 规模与行业地位 | 2024 年销售收入 8621 亿元人民币,全球通信设备第一梯队 |
| 研发与专利 | 2024 年研发费用 1797 亿元,占收入 20.8% |
1.2岗位定位
OD 的 Java 开发岗以业务系统交付为主:接需求、做设计、写代码、联调上线,与自有员工的日常工作几乎一致。区别在劳动关系与晋升体系——由服务商签约,绩效达标且有名额时才有转正机会。对候选人来说,这类岗位的价值在于能进入体量更大、流程更规范的研发体系。
| 所属体系 | 各产品线的项目组,按业务线分配 |
| 核心职责 | 业务系统开发、接口设计、线上问题定位 |
| 发展路径 | OD 开发 → 高级 OD 开发 → 绩效达标后申请转正 |
| 培养体系 | 导师制 + 项目实战,考核以交付质量与协作评价为主 |
- OD 流程前置有在线性格测试,HR 会提示答题倾向,但不要答得过于极端
- 技术一面的八股密度高、覆盖面广,是主要的分水岭
- 手撕必须用目标岗位的语言,投 Java 岗就用 Java 写
1.3招聘概况
OD 招聘全年滚动,流程比校招短:简历筛选 → 性格测试 → 资面 → 技术一面 → 技术二面 → 主管面 → offer。性格测试与资面属于筛选环节,技术面才是真正的分水岭,一般两轮技术面当天或隔天完成。
| 招聘规模 | 按项目组缺口滚动招聘 |
| 面向专业 | 计算机、软件工程等相关专业,本科及以上 |
| 工作地点 | 深圳、东莞、西安、南京、成都等 |
| 投递窗口 | 全年开放 |
企业概况整理自公司官网、公开年报与招聘公告,具体数据以官方最新发布为准。
二、面试总体概述
2.1案例背景
这位同学走的是华为 OD 通道,流程从在线性格测试开始,通过后是资面,再到技术一面与技术二面。技术一面是典型的高密度八股,覆盖 HashMap、并发、锁、缓存、数据库隔离级别,最后手撕三数之和;技术二面则完全转向项目,逐条问「为什么这么实现」并追加限制条件,最后手撕力扣 809。主管面尚未进行。
2.2基本信息
| 公司 | 华为技术有限公司 |
| 岗位 | OD · Java 开发 |
| 用工形式 / 部门 | OD(外包) |
| 面试轮次 | 2 轮 |
| 平均时长 | 52 分钟 |
| 题目数量 | 共 20 题,均附参考答案 |
| 整体难度 | ★★★☆☆ 中等 |
| 候选人背景 | 经历 Java 后端,具备项目开发经验 |
| 是否参加笔试 | 是 |
| 笔试形式 | 在线性格测评 |
2.3高频考点
| 考点 | 分类 | 出现轮次 | 次数 |
|---|---|---|---|
| HashMap 底层与负载因子 | 基础八股 · 集合 | 技术一面 | 2 |
| 并发与锁(AQS / CAS / 锁分类) | 基础八股 · 并发 | 技术一面 | 3 |
| 包装类型与 equals / hashCode | 基础八股 · 语言 | 技术一面 | 3 |
| 缓存三大问题 | 基础八股 · 缓存 | 技术一面 | 1 |
| MySQL 事务与隔离级别 | 基础八股 · 数据库 | 技术一面 | 2 |
| 项目设计决策与方案演进 | 项目经历 | 技术二面 | 3 |
| 手撕(双指针 / 字符串分组) | 算法 | 技术一面、技术二面 | 2 |
2.4备考建议
| 优先级 | 易失分点 | 准备动作 |
|---|---|---|
| P0 | 八股覆盖广但都答不深,容易在并发与集合上失分 | 按「HashMap → 并发(AQS/CAS/锁)→ 集合对比 → 缓存 → 数据库」五条线各整理一页纸,每条能讲 2 分钟 |
| P0 | 包装类型比较用 == 导致代码出错 | 牢记 Integer 缓存池范围,包装类型一律用 equals 或先拆箱;把这条写进自己的编码检查清单 |
| P1 | 项目只会讲实现,答不出「为什么不选另一个方案」 | 每个关键决策做一张 A/B 对比卡:两个方案的收益、代价、适用条件 |
| P1 | 手撕时用错语言或忽略去重细节 | 按目标岗位语言刷 10 道高频题,重点练去重、边界与自测流程 |
三、面试流程
3.1流程总览
| # | 环节 | 形式 | 时长 | 筛选重点 |
|---|---|---|---|---|
| 1 | 简历投递 | 招聘平台 / 服务商渠道 | 1~2 天 | 年限与技术栈匹配 |
| 2 | 性格测试 | 在线测评 | 约 30 分钟 | 性格倾向与岗位匹配 |
| 3 | 资面 | 电话 / 视频 | 约 20 分钟 | 履历真实性、期望薪资、稳定性 |
| 4 | 技术一面 | 视频面试 | 约 60 分钟 | Java 八股广度 + 一道手撕 |
| 5 | 技术二面 | 视频面试 | 约 45 分钟 | 项目深度、方案权衡、一道手撕 |
| 6 | 主管面 | 视频面试 | 约 30 分钟 | 稳定性、协作、对 OD 的认知 |
3.2各环节说明
由服务商的招聘顾问对接,核对年限、期望薪资与到岗时间后推给业务侧。
- 简历突出 Java 技术栈与项目量级
对接的 HR 通常会提示答题倾向(比如稳定性、抗压、团队配合相关的维度要往积极方向答)。测试在工作日提交后一般 1~2 个工作日出结果。
- 前后答案保持一致,别在同类题上自相矛盾
- 不要选极端选项,除非确实符合
问校园或工作经历、遇到的最大困难怎么解决、期望薪资、换城市能否适应这类问题。HR 会提示回答方向,当天就能出结果。
- 期望薪资给一个区间,并说明依据
- 换城市的问题要提前想清楚,不要临场犹豫
面试官会顺着简历问项目,然后铺开一轮八股:集合、并发、锁、缓存、数据库,每个方向都有涉及但不深入,最后给一道力扣题。
- 八股按「结构—原理—使用场景」三段准备
- 手撕用目标岗位语言写,别用自己顺手的其他语言
纯项目深挖,会顺着你的实现往深里推:为什么这么设计、有没有更优方案、加限制条件后怎么做,最后一道字符串处理题。反馈很快,通常十分钟内出结果。
- 每个技术选型准备一个被淘汰的替代方案
- 把「加限制条件」当成常规追问来准备
本次记录中该环节尚未进行。按 OD 的常规节奏,主管面会关注离职原因、加班接受度、对 OD 身份的认知与长期打算。
- 提前想清 OD 的接受边界与转正预期
- 准备一个能体现主动性的项目故事
四、第 1 轮:技术一面
4.1面试形式与时长
| 轮次名称 | 技术一面 |
| 面试类型 | 技术面 |
| 时长 | 60 分钟 |
| 形式 | 视频面试 |
| 本轮题量 | 16 题 |
4.2重点考查维度
- 基础八股 —— 本组 15 道题
- 算法手撕 —— 本组 1 道题
八股密度很高,几乎每个方向都会碰一下:集合、并发、锁、缓存、数据库、语言基础。面试官对深度要求不算苛刻,但要能连续答下来不卡壳。手撕给的是力扣原题,本地 IDE 或共享编辑器都可能。
4.3面试真题与参考答案
从结构、定位、冲突、扩容四点讲。
- 结构:数组 + 链表 + 红黑树。JDK 8 起链表长度到 8 且数组长度不小于 64 时转红黑树,退化到 6 再转回链表。
- 定位:key 的 hashCode 经扰动(高 16 位与低 16 位异或)后,用
(n-1) & hash定位桶,等价于取模但更快(n 是 2 的幂)。 - 冲突:同桶元素先比 hash 再比
equals,都用==优先比较引用,避免不必要的 equals 调用。 - 扩容:默认容量 16、阈值 12,元素数超阈值翻倍。JDK 8 用高低位拆分迁移(hash & oldCap 判断放原位置还是原位置+oldCap),不再重算 hash,也不再有 1.7 头插法成环的问题。
- 线程安全:HashMap 并发 put 会丢数据甚至死循环(1.7),并发场景用 ConcurrentHashMap。
本质是「空间与冲突概率的折中」,不是一个随意取值。
- 定义:负载因子 = 元素数 / 桶数组长度,0.75 意味着装到 3/4 就扩容。
- 冲突与性能:因子过高,桶内链表变长,查询从 O(1) 退化;因子过低,扩容频繁,空间浪费大。
- 数学依据:官方注释里给了泊松分布的分析——在 0.75 的负载下,桶内元素个数服从参数约 0.5 的泊松分布,链表长度达到 8 的概率约为千万分之六,这也是树化阈值取 8 的原因。
- 工程权衡:0.75 让平均查找长度与空间开销都比较均衡,实践中几乎不需要改。
追问预警:如果明确知道元素数量,可以在构造时指定初始容量(预估数量 / 0.75 + 1),避免多次扩容。
标准说法是四种,实际开发常用的是后两种。
- 继承 Thread:重写 run,简单但占用了唯一的继承位,不推荐。
- 实现 Runnable:把任务与线程解耦,无返回值、不能抛受检异常。
- 实现 Callable:有返回值、可以抛异常,配合 FutureTask 或线程池使用。
- 使用线程池(ExecutorService):工程上的标准做法,复用线程、控制并发数、统一异常处理。
补充:严格来说只有「继承 Thread」和「实现 Runnable」是创建线程的方式,Callable 与线程池都是 Runnable 的包装。
追问预警:为什么不推荐 new Thread()——无法复用、无界创建会打爆内存,且缺少统一的生命周期管理。
关键是「返回值怎么跨线程传回来」。
- 定义:
Callable<V>只有一个V call() throws Exception,允许返回值和抛出受检异常,弥补 Runnable 只能void run()的不足。 - 原理:Callable 本身不直接跑在线程里,要包一层 FutureTask。FutureTask 实现 Runnable,内部持有 Callable、一个
state状态位和outcome结果字段。 - 流程:
run()里调用call(),把结果存进outcome,把 state 从 NEW 改为 COMPLETING 再改为 NORMAL;调用get()时若未完成就挂到 waiters 队列上等待,完成后被唤醒并返回 outcome。 - 异常:call 抛出的异常会被捕获并存入 outcome,get 时以 ExecutionException 形式抛出,原始异常在 cause 里。
- 好处:把「异步执行」与「结果获取」统一成一套模型,这也是线程池 submit 能返回 Future 的原因。
AQS(AbstractQueuedSynchronizer)是 Java 并发包的基石,ReentrantLock、Semaphore、CountDownLatch 都基于它。
- 核心三件套:一个 volatile int state(同步状态)、一个 FIFO 双向等待队列(CLH 变体)、以及 Condition 条件队列。
- 获取:tryAcquire 由子类实现(ReentrantLock 里就是 CAS 把 state 从 0 改成 1,重入则 state+1),失败则把当前线程包装成 Node 入队并 park。
- 释放:tryRelease 成功后,唤醒队首的后继节点,让它重新竞争。
- 两种模式:独占(Exclusive)与共享(Shared),CountDownLatch 用共享模式实现多个线程同时等待。
- 公平与非公平:公平锁入队前先检查有没有前驱,非公平锁直接抢,吞吐更高但可能饿死。
- 为什么高效:CAS 自旋 + park/unpark 阻塞,避免了无谓的 CPU 空转;队列操作只在必要时加锁。
CAS(Compare And Swap)是一条 CPU 原子指令,包含三个操作数:内存地址 V、期望值 A、新值 B。仅当 V 的当前值等于 A 时才把 V 更新为 B,否则失败重试。
- Java 实现:
Unsafe.compareAndSwapInt,底层是cmpxchg指令,多核下会加 lock 前缀保证原子性与可见性。 - 优点:无锁、不阻塞线程、没有上下文切换开销,适合竞争不激烈的场景(AtomicInteger 计数)。
- 问题一 ABA:值从 A 改成 B 又改回 A,CAS 察觉不到。解法是加版本号(AtomicStampedReference)。
- 问题二 自旋开销:竞争激烈时大量失败重试,CPU 空转。解法是限制自旋次数、退化为加锁,或参考 LongAdder 的分段累加。
- 问题三 只能保证单个变量:多变量要封装成对象用 AtomicReference。
指缓存穿透、缓存击穿、缓存雪崩三个典型问题。
- 穿透:查询的 key 在缓存和数据库里都不存在,请求全部打到数据库。解法是缓存空值(设短过期时间)或用布隆过滤器提前拦截。
- 击穿:某个热点 key 过期瞬间,大量并发同时打到数据库。解法是加互斥锁(只让一个线程回源)、逻辑过期(不设物理过期,异步刷新)、或热点数据永不过期。
- 雪崩:大量 key 在同一时刻集体过期,或缓存服务整体宕机。解法是过期时间加随机抖动、多级缓存、缓存集群高可用、以及降级限流兜底。
补充两个常被一起问的:
- 双写一致性:常用「先更新数据库再删缓存」,配合延迟双删或 binlog 订阅补偿。
- 热 key 与大 key:本地缓存 + 拆分,避免单节点压力倾斜。
八种,按是否带小数分两类。
- 整数:byte(1 字节,-128~127)、short(2 字节)、int(4 字节)、long(8 字节)。
- 小数:float(4 字节,单精度)、double(8 字节,双精度)。
- 字符:char(2 字节,无符号,存 Unicode 码元)。
- 布尔:boolean(JVM 规范未规定大小,实际常按 1 字节或 4 字节处理)。
对比要点:
- 包装类型(Integer/Long/Double…)是对象,可以参与泛型、可以为 null,但比较必须用 equals。
- 自动装箱有缓存:Integer 默认缓存 -128~127,所以这个区间内
==成立。 - 金额用 BigDecimal,不要用 double——二进制浮点无法精确表示 0.1。
一句话:HashSet 内部就是一个 HashMap,元素作为 key,value 是一个固定的占位对象(PRESENT)。
- 添加:
add(e)实际调用map.put(e, PRESENT),返回值为 null 表示新增成功,非 null 表示元素已存在。 - 去重:靠 HashMap 的 key 唯一性——先比 hash,再用
equals判断,所以自定义对象必须同时重写hashCode与equals,只重写一个会出现「重复元素加不进去」或「不同对象被判为重复」。 - 无序:存取顺序与哈希分布有关,不保证插入顺序;要保序用 LinkedHashSet,要排序用 TreeSet。
- 复杂度:平均 O(1),最坏(大量冲突退化为链表)O(n)。
- 非线程安全:并发场景用
Collections.newSetFromMap(new ConcurrentHashMap<>())。
从底层结构推到使用场景。
- 结构:ArrayList 是动态数组,内存连续;LinkedList 是双向链表,每个节点额外存前后指针。
- 随机访问:ArrayList O(1);LinkedList O(n),必须从头或尾遍历。
- 增删:ArrayList 在尾部追加均摊 O(1),中间插入要移动元素 O(n);LinkedList 定位到位置本身是 O(n),定位后改指针 O(1),所以「LinkedList 增删快」只在已有节点引用时成立。
- 内存:ArrayList 有扩容时的数组拷贝与空间预留;LinkedList 每个节点有额外指针开销,且节点分散不利于 CPU 缓存。
- 实践建议:绝大多数场景用 ArrayList,即使频繁在头部操作;需要队列语义用 ArrayDeque,它比 LinkedList 更快。
按不同维度分类,别混着讲。
- 按是否阻塞:悲观锁(先加锁再操作,如 synchronized、ReentrantLock)与乐观锁(CAS 或版本号,冲突时重试)。
- 按特性:公平锁 / 非公平锁(能否插队)、可重入锁 / 不可重入锁、独享锁 / 共享锁(读锁是共享)、分段锁(ConcurrentHashMap 1.7 的思想)。
- 按实现:synchronized(JVM 层面,monitor 实现,1.6 后有偏向锁、轻量级锁、重量级锁的升级)、ReentrantLock(AQS 实现,可中断、可超时、可多条件)、读写锁 ReentrantReadWriteLock、StampedLock(乐观读)。
- 选择建议:简单同步用 synchronized(JVM 会优化);需要可中断、超时、公平或条件变量时用 ReentrantLock;读多写少用读写锁。
追问预警:synchronized 的锁升级过程与对象头 Mark Word 的关系。
因为 Integer 内部有缓存池。
- 机制:
Integer.valueOf(int)在 -128~127 范围内返回IntegerCache.cache[i + 128]这个预先创建好的对象,超出范围才new Integer(i)。 - 所以两个 100 的 Integer 指向同一个缓存对象,
==比较引用自然为 true;而 200 会各自 new,==为 false。 - 为什么是 -128~127:这是 byte 的取值范围,覆盖了最常见的计数场景;上限可用
-XX:AutoBoxCacheMax调整。 - 正确做法:包装类型比较值一律用
equals,或用Objects.equals;也可以先拆箱成基本类型再比。 - 更隐蔽的坑:
Integer a = 100; Integer b = 100; a == b为 true,但new Integer(100) == new Integer(100)永远为 false。
==:对基本类型比的是值,对引用类型比的是「是否指向同一个对象」(地址)。equals:Object 的默认实现就是==,但 String、Integer 等类重写成了比内容。所以能不能比值,取决于有没有重写。- 契约:重写 equals 必须同时重写 hashCode,否则放进 HashMap/HashSet 会出问题——两个 equals 相等的对象 hashCode 不同,会被分到不同的桶。
- 五个约定:自反、对称、传递、一致、与 null 比较返回 false。
- 实践:比较字符串用
Objects.equals(a, b),或把常量写在前面(如"abc".equals(x))避免 NPE;枚举用==更安全。
追问预警:为什么重写 equals 一定要重写 hashCode——反例是两个内容相同的对象 hashCode 不同,map.get 拿不到值。
四个特性对应四种机制。
- 原子性(A):事务里的操作要么全成功要么全回滚。由 undo log 保证——修改前的旧值记在 undo log 里,失败时反向执行。
- 一致性(C):事务前后数据满足业务约束。这是目的而不是手段,由 A、I、D 加上业务约束共同保证。
- 隔离性(I):并发事务之间互不干扰。由锁(行锁、间隙锁)与 MVCC(版本链 + ReadView)共同实现。
- 持久性(D):提交后即使断电也不丢。由 redo log + WAL 机制保证——先写日志再刷数据页,崩溃后用 redo 重放。
追问预警:redo log 与 binlog 的两阶段提交(prepare → commit),目的是保证两份日志一致,避免主从数据不一致。
四种,按隔离强度递增。
- 读未提交(Read Uncommitted):能读到其他事务未提交的数据,会脏读,几乎不用。
- 读已提交(Read Committed):只能读已提交的数据,解决脏读,但同一事务内两次读可能不同(不可重复读)。Oracle、PostgreSQL 的默认级别。
- 可重复读(Repeatable Read):同一事务内多次读结果一致,解决不可重复读;MySQL 的默认级别,通过 MVCC 的 ReadView 实现。
- 串行化(Serializable):加锁串行执行,解决幻读,但并发性能最差。
关键点:MySQL 的 RR 级别在「快照读」下靠 MVCC 避免幻读,「当前读」下靠间隙锁(Next-Key Lock)避免幻读,所以严格说 RR 也能防幻读,这是 InnoDB 与标准定义的差异。
追问预警:MVCC 的 ReadView 里四个字段(m_ids、min_trx_id、max_trx_id、creator_trx_id)怎么判断可见性。
题目:给定数组 nums,找出所有和为 0 且不重复的三元组。
思路:排序 + 固定第一个数 + 双指针。排序后可以跳过重复元素,也保证了双指针收缩的方向性。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
for (int i = 0; i < nums.length - 2; i++) {
if (nums[i] > 0) break; // 最小的都大于 0,后面不可能有解
if (i > 0 && nums[i] == nums[i - 1]) continue; // 跳过重复的第一个数
int l = i + 1, r = nums.length - 1;
while (l < r) {
int sum = nums[i] + nums[l] + nums[r];
if (sum == 0) {
res.add(Arrays.asList(nums[i], nums[l], nums[r]));
while (l < r && nums[l] == nums[l + 1]) l++; // 跳过重复的第二个数
while (l < r && nums[r] == nums[r - 1]) r--;
l++; r--;
} else if (sum < 0) l++;
else r--;
}
}
return res;
}
}三个坑:① 三层去重都要做(i、l、r),漏一层就会出重复三元组;② 提前 break 的条件是 nums[i] > 0 而不是 >= 0;③ 如果用 List 存结果并用 indexOf 去重,注意 Integer 比较必须用 equals,不能用 ==。
复杂度:O(n²) 时间,O(1) 额外空间(不含结果集)。
五、第 2 轮:技术二面
5.1面试形式与时长
| 轮次名称 | 技术二面 |
| 面试类型 | 技术面 |
| 时长 | 45 分钟 |
| 形式 | 视频面试 |
| 本轮题量 | 4 题 |
5.2重点考查维度
- 项目经历 —— 本组 3 道题
- 算法手撕 —— 本组 1 道题
纯项目,一条一条往下问,会追加限制条件看你怎么应变。八股一个都没问,直接进入手撕环节。反馈速度极快,面完十分钟内出结果。
5.3面试真题与参考答案
二面的问法是「顺着实现反推决策」,每一层都要有一句理由。
- 先给约束:当时的并发量、数据量、交付时间、团队技术栈,理由必须挂在约束上。
- 再给选择:为什么用这张表/这个缓存/这个中间件,而不是另一个。
- 给代价:这个选择带来了什么问题(一致性变弱、运维复杂),后来怎么补的。
- 给边界:什么情况下这个方案会失效,届时的演进方向是什么。
面试官常追问「如果当时选另一个会怎样」,准备时把每个关键决策做成 A/B 对比,是最有效的办法。
提醒:不要把所有决策都说成自己拍的板,团队约束讲清楚反而更可信。
这类问题考的是「方案的可延展性」,按三层答。
- 现状层:当前方案的瓶颈在哪(数据库压力、接口串行、缓存命中率低)。
- 优化层:给 2~3 个方向并排序——加缓存、异步化、读写分离、分库分表、批量化。每个方向说清收益与改动成本。
- 限制层:面试官加的限制通常是「不能加机器」「不能改表结构」「延迟要压到 50ms」,这时答案要随之收敛,比如只能做本地缓存 + 结果合并。
- 收尾:给出你的推荐方案与理由,说明为什么现在不做其他方案。
一个加分细节:主动提「优化的前提是先有度量」,说清你会先看哪些指标再动手。
选「有约束、有取舍、有结果」的难点,避免纯知识型问题。
- 难点举例:数据迁移不能停机、缓存与库不一致、消息重复消费导致对账不平。
- 约束:数据量多大、可接受的不一致窗口、团队人力与时间。
- 方案:先定位根因,再给分层防护(本地消息表 + 定时补偿 + 对账兜底),最后灰度验证。
- 结果:问题率从多少降到多少,是否有返工。
- 沉淀:把这次的经验做成了什么规范或工具。
结尾补一句「难的不是方案,是让所有人都按同一个约定实现」,把技术问题落到协作上,二面主管很吃这一套。
题目:给定字符串 s 和单词数组 words,统计 words 中有多少个单词可以由 s「扩张」得到。扩张规则是:把连续相同字符的一组(长度 n)扩成不少于 3 个且不等于原长度的任意长度,即新长度 m 满足 m ≥ 3 且 m ≠ n;若 n < 3 则不能扩张,必须相等。
思路:把 s 和每个 word 都按「连续相同字符」分组,得到 (字符, 长度) 序列,然后逐组比较。
- 组数必须相同,且每组字符相同。
- 长度比较:若 word 组长度 a、s 组长度 b——
a == b合法(不扩张);a < b时要求a >= 3(可以扩到 b,且 b ≠ a 自动满足);a > b不合法。
def expressiveWords(s, words):
def group(t):
res = []
i = 0
while i < len(t):
j = i
while j < len(t) and t[j] == t[i]:
j += 1
res.append((t[i], j - i))
i = j
return res
gs = group(s)
ans = 0
for w in words:
gw = group(w)
if len(gw) != len(gs):
continue
ok = True
for (c1, a), (c2, b) in zip(gw, gs):
if c1 != c2 or a > b or (a < b and a < 3):
ok = False
break
ans += 1 if ok else 0
return ans验证:s 为 heeellooo、words 为 ["hello","hi","helo"] 时返回 1(只有 hello 能扩成 heeellooo)。
边界:空字符串、单字符组、group 数量不等直接判不合法。复杂度 O(len(s) + 所有单词长度之和)。
六、注意事项
OD 的技术面难度中等,真正拉开差距的是八股的连贯性和手撕的语言选择。
投 Java 岗就用 Java 写。日常用 C++ 或 Python 刷题的人,现场用 Java 会写得很别扭,尤其在集合与类型比较上容易出错。
三数之和对撞去重、缓存 key 比较、结果去重,只要用到 == 比 Integer 就可能出错。统一改用 equals 或先拆箱,并在自测时专门验证一次。
一面每个方向都会问,答一句就卡住很伤。按「结构—原理—场景」三段背,保证每道题都有 2 分钟的存量。
0.75 要能扯到空间与冲突的折中、泊松分布、以及树化阈值取 8 的原因,只答「官方推荐」会被追问到没话说。
HR 会提示倾向,但同一维度反复出现时答案要一致。选得过于极端或自相矛盾,可能在技术面之前就被筛掉。
面试官一定会问「有没有更好的方案」「加个限制你会怎么做」。准备时把每个决策的替代方案与代价写下来,别临场编。
期望薪资、换城市、到岗时间这三件事在资面就会被问到,口径定了就不要在后续环节改口。
总结收尾
这份记录的价值在于把 OD 的完整链路摊开了:性格测试与资面是筛人,技术一面是刷八股广度,技术二面是验项目真实性。一面的八股看似零散,其实集中在五条线上——集合、并发、包装类型与 equals、缓存、数据库事务,按线准备比按题准备效率高得多。二面则要习惯「加限制条件」的追问方式,随时能给出退一步的可行方案。最后提醒一句:手撕选语言这件事,现场真的会决定成败。
在此推荐你使用求职精灵(https://finsight.work/)进行系统备考。平台拥有华为等数百家知名企业的真实面经资源,独家支持中英双语 AI 模拟面试,可针对OD · Java 开发进行定制化练习和智能评分优化;简历智能修改功能帮你打磨出一份亮眼的简历;超过 15 万道行测、专业题、英语题随时随地在线刷题。无论你是第一次校招还是已经面过几轮,求职精灵都能为你的求职之路提供有力支持。