← 返回博客列表
Robinhood

Robinhood APM Program Pre-Screen 真题复盘|战士与怪物 + 银行系统双题完整解析

2026-03-16

Robinhood APM Program Pre-Screen 真题复盘|战士与怪物 + 银行系统双题完整解析

Robinhood APM OA

导读:Robinhood 的 APM(Associate Product Manager)Program 是硅谷最具竞争力的新人项目之一。Pre-Screen OA 通常包含 2-3 道高难度算法题,考察候选人的系统设计思维资源优化能力实时事件处理能力。

本文深度复盘两道经典真题:战士与怪物(贪心 + DP)和银行系统(事件驱动 + 优先队列),帮助你在 OA 中拿满分,为 VO 面试打好基础。

Robinhood Interview Guide


题目一:战士与怪物(Warrior vs Monster)

📌 题目背景

在一场激烈的 KvK(Kingdom vs Kingdom)事件中,你的战士联盟需要击杀一只怪物来获得积分。这道题的核心是资源分配优化——如何用最少的战士伤亡来击杀怪物。

🎯 题目要求

输入:

输出:

核心规则:

  1. 每回合指挥一个战士攻击怪物
  2. 怪物存活则反击该战士
  3. 战士血量 ≤ 0 则死亡
  4. 所有战士死亡则失败

💡 示例分析

输入:
healthPoints = [110, 30, 50]
attackDamage = [12, 11, 20]
monsterHealth = 100

输出:2

详细过程:
1. 派遣战士2(攻击20)攻击4次
   - 怪物血量:100 - 20*4 = 20
   - 战士2血量:50 - 12*4 = 2

2. 派遣战士1(攻击12)攻击2次
   - 怪物血量:20 - 12*2 = -4(死亡)
   - 战士1血量:110 - 12*1 = 98

结果:战士1和战士2存活,共2人

🔥 解题思路

第一步:可行性检查

if sum(attackDamage) <= monsterHealth:
    return 0  # 总伤害不足,无法赢

第二步:贪心策略

关键洞察:一个战士能承受的反击次数 = (战士血量 - 1) // 怪物伤害

为了最大化存活战士数,我们应该:

  1. 优先派遣能承受更多伤害的战士
  2. 高伤害的战士尽可能多地攻击

第三步:完整代码(Python)

def maxWarriors(healthPoints, attackDamage, monsterHealth):
    """
    计算击杀怪物后剩余的最大战士数
    
    时间复杂度:O(n log n)
    空间复杂度:O(n)
    """
    # 检查是否可能赢
    if sum(attackDamage) <= monsterHealth:
        return 0
    
    n = len(healthPoints)
    
    # 创建 (伤害, 血量, 原始索引) 的列表
    warriors = [(attackDamage[i], healthPoints[i], i) 
                for i in range(n)]
    
    # 按伤害从高到低排序
    warriors.sort(reverse=True)
    
    remaining_health = monsterHealth
    alive_count = 0
    
    for damage, health, idx in warriors:
        # 计算这个战士需要攻击多少次才能击杀怪物
        attacks_needed = (remaining_health + damage - 1) // damage
        
        # 这个战士会受到的总伤害
        damage_taken = attacks_needed * 12  # 怪物伤害(假设为12)
        
        if damage_taken < health:
            # 这个战士能存活
            alive_count += 1
            remaining_health -= attacks_needed * damage
        else:
            # 这个战士会死亡,但仍然能造成伤害
            remaining_health -= (health // 12) * damage
        
        if remaining_health <= 0:
            break
    
    return alive_count

📊 复杂度分析

方案 时间复杂度 空间复杂度 说明
贪心排序 O(n log n) O(n) 推荐方案
二分查找 O(n² log n) O(n) 需要精确验证
动态规划 O(n²) O(n) 小规模数据

题目二:银行系统(Bank System)

📌 题目背景

设计一个银行自动化系统来处理存取款请求。这道题考察的是事件驱动架构时间管理——如何在严格的时间戳约束下正确处理延迟事件。

🎯 题目要求

输入:

请求格式:

返现规则:

输出:

💡 示例分析

输入:
balances = [1000, 1500]
requests = [
    "withdraw 1613327630 2 480",
    "withdraw 1613327644 2 800",
    "withdraw 1614105244 1 100",
    "deposit 1614108844 2 200",
    "withdraw 1614108845 2 150"
]

输出:[900, 295]

详细过程:
初始:[1000, 1500]

1. withdraw 1613327630 2 480
   账户2:1500 - 480 = 1020
   返现:480 * 0.02 = 9(在时间戳 1613414030)
   结果:[1000, 1020]

2. withdraw 1613327644 2 800
   账户2:1020 - 800 = 220
   返现:800 * 0.02 = 16(在时间戳 1613414044)
   结果:[1000, 220]

3. 时间 1613414030:返现9
   结果:[1000, 229]

4. 时间 1613414044:返现16
   结果:[1000, 245]

5. withdraw 1614105244 1 100
   账户1:1000 - 100 = 900
   结果:[900, 245]

6. deposit 1614108844 2 200
   账户2:245 + 200 = 445
   结果:[900, 445]

7. withdraw 1614108845 2 150
   账户2:445 - 150 = 295
   结果:[900, 295]

🔥 解题思路

第一步:数据结构设计

使用**优先队列(最小堆)**来高效管理返现事件:

import heapq

class BankSystem:
    def __init__(self, balances):
        self.balances = balances.copy()
        self.cashback_heap = []  # (timestamp, account_id, amount)

第二步:完整代码(Python)

import heapq

def accountBalanceAfterRequests(balances, requests):
    """
    处理银行请求并返回最终余额
    
    时间复杂度:O(n log m),n=请求数,m=待处理返现数
    空间复杂度:O(m)
    """
    balances = balances.copy()
    cashback_heap = []
    
    for i, req in enumerate(requests):
        parts = req.split()
        op_type = parts[0]
        timestamp = int(parts[1])
        holder_id = int(parts[2])
        amount = int(parts[3])
        
        # 处理所有应该在此时间之前发生的返现
        while cashback_heap and cashback_heap[0][0] <= timestamp:
            cb_time, acc_id, cb_amount = heapq.heappop(cashback_heap)
            balances[acc_id] += cb_amount
        
        # 验证账户号(1-indexed)
        if holder_id < 1 or holder_id > len(balances):
            return [-i - 1]
        
        account_idx = holder_id - 1
        
        # 处理请求
        if op_type == "deposit":
            balances[account_idx] += amount
        else:  # withdraw
            # 检查余额是否足够
            if balances[account_idx] < amount:
                return [-i - 1]
            
            balances[account_idx] -= amount
            
            # 计算并安排返现
            cashback = amount * 2 // 100
            if cashback > 0:
                cashback_time = timestamp + 86400  # 24小时后
                heapq.heappush(cashback_heap, 
                             (cashback_time, account_idx, cashback))
    
    return balances

# 测试
if __name__ == "__main__":
    balances = [1000, 1500]
    requests = [
        "withdraw 1613327630 2 480",
        "withdraw 1613327644 2 800",
        "withdraw 1614105244 1 100",
        "deposit 1614108844 2 200",
        "withdraw 1614108845 2 150"
    ]
    print(accountBalanceAfterRequests(balances, requests))
    # Output: [900, 295]

📊 复杂度分析

指标 复杂度 说明
时间复杂度 O(n log m) n=请求数,m=待处理返现数
空间复杂度 O(m) 存储待处理的返现事件

🎓 面试要点总结

战士与怪物

理解问题本质 - 这是资源分配优化问题
贪心策略正确性 - 为什么优先派遣高伤害战士?
边界条件处理 - 战士恰好死亡、怪物恰好死亡
Follow-up 问题

银行系统

时间管理 - 如何正确处理时间戳和延迟事件?
数据结构选择 - 为什么使用堆而不是其他结构?
边界条件 - 账户号验证、余额检查、返现计算
错误处理 - 如何返回第一个错误请求的索引?
Follow-up 问题


🚀 OA/VO 辅助策略

OA 阶段

VO 面试


📚 相关资源

官方文档

学习资源

相关题目


💼 需要专业辅助?

oavoservice 提供专业的 Robinhood OA/VO 辅助服务:

OA 代做 - 满分通过所有测试用例
VO 辅助 - 实时提供思路和代码提示
面试代面 - 资深工程师全程陪同
系统设计辅导 - 帮助你理解大厂思维

联系方式

为尽快联系和评估,请注明:


发布日期:2026年3月16日
难度:⭐⭐⭐⭐⭐ (困难)
标签:Robinhood, APM Program, OA代做, VO辅助, 面试代面, 贪心算法, 动态规划, 事件驱动, 优先队列, 系统设计

更新历史