Robinhood APM Program Pre-Screen 真題複盤|戰士與怪物 + 銀行系統雙題完整解析

導讀:Robinhood 的 APM(Associate Product Manager)Program 是矽谷最具競爭力的新人項目之一。Pre-Screen OA 通常包含 2-3 道高難度算法題,考察候選人的系統設計思維、資源優化能力和實時事件處理能力。
本文深度複盤兩道經典真題:戰士與怪物(貪心 + DP)和銀行系統(事件驅動 + 優先隊列),幫助你在 OA 中拿滿分,為 VO 面試打好基礎。

題目一:戰士與怪物(Warrior vs Monster)
📌 題目背景
在一場激烈的 KvK(王國對王國)事件中,你的戰士聯盟需要擊殺一隻怪物來獲得積分。這道題的核心是資源分配優化——如何用最少的戰士傷亡來擊殺怪物。
🎯 題目要求
輸入:
healthPoints: 戰士血量陣列attackDamage: 戰士攻擊傷害陣列monsterHealth: 怪物血量
輸出:
- 擊殺怪物後剩餘的最大戰士數量
- 如果無法擊殺,返回 0
核心規則:
- 每回合指揮一個戰士攻擊怪物
- 怪物存活則反擊該戰士
- 戰士血量 ≤ 0 則死亡
- 所有戰士死亡則失敗
💡 示例分析
輸入:
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) // 怪物傷害
為了最大化存活戰士數,我們應該:
- 優先派遣能承受更多傷害的戰士
- 讓高傷害的戰士盡可能多地攻擊
第三步:完整代碼(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: 初始帳戶餘額陣列requests: 交易請求列表
請求格式:
deposit <timestamp> <holder_id> <amount>- 存款withdraw <timestamp> <holder_id> <amount>- 取款(帶2%返現)
返現規則:
- 取款金額的2%(向下取整)在24小時後返還
- 如果返現和其他操作在同一時間戳,返現優先處理
輸出:
- 最終餘額陣列,或返回
[-request_id]表示第一個錯誤請求
💡 示例分析
輸入:
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 階段
- ⏱️ 時間管理:兩道題通常限時 90 分鐘,建議 40 分鐘/題
- 💻 代碼質量:注重邊界條件和錯誤處理
- 📝 註釋清晰:讓面試官快速理解你的思路
VO 面試
- 🎤 清晰表達:用簡單的語言解釋複雜的算法
- 🔍 深度討論:準備好 Follow-up 問題的答案
- 🏗️ 系統思維:展示你對整體架構的理解
📚 相關資源
官方文檔
學習資源
相關題目
- LeetCode 1882 - Process Tasks Using Servers
- LeetCode 2402 - Meeting Rooms III
- LeetCode 1834 - Single-Threaded CPU
💼 需要專業輔助?
oavoservice 提供專業的 Robinhood OA/VO 輔助服務:
✅ OA 代做 - 滿分通過所有測試用例
✅ VO 輔助 - 實時提供思路和代碼提示
✅ 面試代面 - 資深工程師全程陪同
✅ 系統設計輔導 - 幫助你理解大廠思維
聯絡方式
- 📱 微信:Coding0201
- 💬 Telegram:@OAVOProxy
- 📧 郵箱:[email protected]
- 🔗 官網:oavoservice.com
為尽快聯絡和評估,請注明:
- 面試公司:Robinhood
- 職位:APM Program
- 面試時間:具體日期
- 需求:OA 代做 / VO 輔助 / 面試代面
發布日期:2026年3月16日
難度:⭐⭐⭐⭐⭐ (困難)
標籤:Robinhood, APM Program, OA代做, VO輔助, 面試代面, 貪心算法, 動態規劃, 事件驅動, 優先隊列, 系統設計
更新歷史:
- 2026-03-16:初版發布,包含兩道題完整解析