← 返回博客列表
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(王國對王國)事件中,你的戰士聯盟需要擊殺一隻怪物來獲得積分。這道題的核心是資源分配優化——如何用最少的戰士傷亡來擊殺怪物。

🎯 題目要求

輸入:

輸出:

核心規則:

  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輔助, 面試代面, 貪心算法, 動態規劃, 事件驅動, 優先隊列, 系統設計

更新歷史