← 返回面经列表

Meta / CodeSignal OA 四题复盘:Q1 数位和贪心,Q2 无人机投递模拟,Q3 电池充放电资源管理,Q4 Two-Sum with Update

3 分钟

这类 OA 的味道很统一:算法不一定难,但规则细、实现步骤多。写对的关键不是“脑补最优策略”,而是把题面约束逐条落成代码。

本文按 Q1→Q4 复盘四题:题意要点、最稳的实现思路、容易翻车的坑点,以及可直接套用的代码模板。

相关延伸阅读:


Q1 — Minimum Sum After One Operation

题目概述

给定正整数数组 nums,最多执行一次操作:

  • 选择一个下标 i
  • nums[i] 替换成它的 各位数字之和

返回执行 0 次或 1 次操作后,数组总和的最小值。

核心思路(热手题)

这题就是“算差值”的贪心:

  • 先算原始总和 S
  • 对每个数 x 计算 digitSum(x)
  • 替换后的总和是 S - x + digitSum(x)
  • 取最小即可(也要考虑“不替换”的情况)

复杂度

  • 时间:O(n * log10(max(nums)))
  • 空间:O(1)

Python 模板

def digit_sum(x: int) -> int:
    s = 0
    while x > 0:
        s += x % 10
        x //= 10
    return s


def min_sum_after_one_operation(nums: list[int]) -> int:
    S = sum(nums)
    ans = S
    for x in nums:
        ans = min(ans, S - x + digit_sum(x))
    return ans

Q2 — Delivery System Using Drones

题目概述

给定 target 距离和一组 stations(一维坐标),你要用“人 + 无人机站点”把货送到 target

无人机规则:

  • 每次从某个 station 放飞无人机,最多飞 10 单位(包括最终那一跳)

并且你必须严格按题目流程重复:

  1. 你从“当前货物位置”带着货走到 最近的 station
  2. 用该 station 的无人机把货送出去(最多 10 单位)
  3. 若无人机没飞到 target:你要 空手 走到货物落点取回货
  4. 重复直到送达 target

返回:你“带着货物步行”的总距离(空手走的不计入)。

易错点(Meta 很爱卡这里)

  • stations 必须先排序,否则最近站点查找很容易写崩
  • 只有带货步行才计入答案,空手追货不计入
  • 规则是“最近站点”,不是“下一个站点 / 往前走的站点”

稳妥模拟策略

只维护一个变量:cargoPos(货物当前在哪)。

每轮:

  • 找到离 cargoPos 最近的站点 s
  • ans += abs(cargoPos - s),然后 cargoPos = s
  • 无人机把货往 target 方向送 <= 10
    • target >= cargoPoscargoPos = min(target, cargoPos + 10)
    • 否则:cargoPos = max(target, cargoPos - 10)
  • 如果没到 target,你空手去取货,这段不计入;下一轮以新的 cargoPos 继续

Python 模板

import bisect


def nearest_station(pos: int, stations: list[int]) -> int:
    # stations 必须已排序
    j = bisect.bisect_left(stations, pos)

    cand = []
    if j < len(stations):
        cand.append(stations[j])
    if j - 1 >= 0:
        cand.append(stations[j - 1])

    # 题面若未定义 tie-break,建议取距离相同则取较小坐标,避免不稳定
    cand.sort(key=lambda s: (abs(s - pos), s))
    return cand[0]


def delivery_distance_with_cargo(target: int, stations: list[int]) -> int:
    stations.sort()

    cargo = 0
    ans = 0

    while cargo != target:
        s = nearest_station(cargo, stations)
        ans += abs(cargo - s)
        cargo = s

        if target >= cargo:
            cargo = min(target, cargo + 10)
        else:
            cargo = max(target, cargo - 10)

        # 若没到 target:空手去拿货(不计入),下一轮继续

    return ans

Q3 — Battery Usage Simulation

题目概述

你想让手机持续运行总时长 t

有若干块电池:

  • capacity[i]:满电可用时长
  • recharge[i]:从 0 充满所需时间

规则:

  • 只能使用 fully-charged 的电池
  • 电池用完后立即开始充电
  • 如果需要用电池但没有任何 fully-charged:返回 -1
  • 还有一个最容易被忽略的规则:最后一块电池如果没用完(导致时间“超出 t”或“提前停”),并且无法满足题面要求的“都在充电状态”,也要返回 -1

实战写法上,最稳的处理是:

  • 你每次选一块可用电池,就必须把它用到耗尽
  • 因此最终要求是:恰好用电池累计到 t(不能 > t

核心模拟

nextFull[i] 表示第 i 块电池下次“充满可用”的时间点。

  • 初始所有电池满电:nextFull[i] = 0
  • 当前时间 cur
  • cur 时刻,所有满足 nextFull[i] <= cur 的电池都可用
  • 用完电池后更新:nextFull[i] = cur + recharge[i]

为了尽量减少使用电池数,直觉上每次优先用 当前可用里 capacity 最大 的那块。

Python 模板(堆)

import heapq


def min_batteries_to_run(t: int, capacity: list[int], recharge: list[int]) -> int:
    n = len(capacity)

    # future: (time_when_full, idx)
    future = [(0, i) for i in range(n)]
    heapq.heapify(future)

    # ready: (-capacity, idx)
    ready = []

    cur = 0
    used = 0

    while cur < t:
        while future and future[0][0] <= cur:
            _, i = heapq.heappop(future)
            heapq.heappush(ready, (-capacity[i], i))

        if not ready:
            return -1

        cap_neg, i = heapq.heappop(ready)
        cap = -cap_neg

        cur += cap
        used += 1

        if cur > t:
            return -1

        heapq.heappush(future, (cur + recharge[i], i))

    return used

Q4 — Primary + Secondary Arrays with Operations

题目概述

给定两个数组 primarysecondary,以及一系列操作 operations

  • [0, index, val]:更新 secondary[index] = val
  • [1, targetSum]:查询满足 primary[i] + secondary[j] == targetSum 的 pair 数量

其中:

  • primary 固定不变
  • secondary 会频繁更新

为什么暴力会超时?

如果你每次 query 都遍历两数组:

  • O(n*m) 直接爆炸

即使你把 primary 先做成 hashmap,再遍历 secondary

  • 每次 query 还是 O(n + m),操作多也扛不住

正解:频率表 + 动态维护

这是面试官最爱给的暗示:

  • “一边 fixed / 一边 dynamic”

做法:

  • primaryfreqA(固定)
  • secondaryfreqB(会变)
  • 更新时:
    • 把旧值从 freqB 里减掉
    • 把新值加进去
  • 查询时:
    • 枚举 freqA 里的 distinct key a
    • 累加 freqA[a] * freqB[targetSum - a]

时间复杂度(关键优势):

  • 更新:O(1)
  • 查询:O(distinct(primary))

Python 模板

from collections import Counter


def process_operations(primary: list[int], secondary: list[int], operations: list[list[int]]) -> list[int]:
    freqA = Counter(primary)
    freqB = Counter(secondary)

    ans = []

    for op in operations:
        if op[0] == 0:
            idx, val = op[1], op[2]
            old = secondary[idx]

            freqB[old] -= 1
            if freqB[old] == 0:
                del freqB[old]

            secondary[idx] = val
            freqB[val] += 1

        else:
            target = op[1]
            total = 0
            for a, cntA in freqA.items():
                total += cntA * freqB.get(target - a, 0)
            ans.append(total)

    return ans

最后:这套四题真正考的是“工程化执行力”

  • Q1:算差值,别上强度
  • Q2:按步骤模拟,别脑补路线
  • Q3:资源状态机(可用 / 充电中),最后的边界条件最阴
  • Q4:固定 + 动态的 Two-Sum 结构,频率表是王道

如果你也在准备 Meta / CodeSignal 类 OA,建议把“模拟题”当成工程题来写:

  • 先列流程
  • 再写状态变量
  • 最后补 tie-break 与边界条件

需要面试真题? 立刻联系微信 Coding0201,获得真题


联系方式

Email: [email protected] Telegram: @OAVOProxy