# 亚马逊 (Amazon) 高级算法工程师面试全攻略 —— 从领导力准则到分布式系统设计(附超详细代码解析)

## 前言:为什么亚马逊的面试被称为“面试界的马拉松”?

亚马逊作为全球最大的电商与云计算公司,其高级算法工程师(Senior Applied Scientist / Senior Algorithm Engineer)的面试流程以**高强度、全维度、深度结合业务场景**而闻名。不同于其他科技巨头仅看重刷题能力,亚马逊独有的 **Bar Raiser** 机制与 **14条领导力准则** 贯穿始终。本文将以超过 **20,000字** 的篇幅(无篇幅限制),彻底拆解从电话初筛到最终Onsite 5-6轮的所有环节,并提供完整的 **文字讲解 + 可运行代码**。无论你瞄准的是Search、Alexa、Supply Chain Optimization还是AWS AI Lab,这篇指南都将成为你的终极面试作战手册。

---

## 第一章:亚马逊面试流程全景与“领导力准则”底层逻辑

### 1.1 面试轮次构成(L5/L6 高级工程师标准)

| 阶段 | 形式 | 考察重点 | 时长 |
| :--- | :--- | :--- | :--- |
| **Phone Screen 1** | 视频 (Coding + ML Breadth) | 代码基本功、ML理论扎实度 | 60 min |
| **Phone Screen 2** (Optional) | 视频 (系统设计/Bar Raiser预备) | 架构感、业务理解 | 60 min |
| **Onsite Loop (5 Rounds)** | 现场或Virtual | **综合战** | 每轮 60 min |

**Onsite Loop 经典分配:**
- **Round 1 & 2:** 算法硬核编码 (LeetCode Medium-Hard, 含变形Follow-up)
- **Round 3:** 机器学习系统设计 (ML System Design)
- **Round 4:** 行为面试 (Behavioral) + 领导力准则深度挖掘
- **Round 5:** Bar Raiser Round (跨部门资深面试官,拥有**一票否决权**)

### 1.2 亚马逊14条领导力准则深度解析与回答框架

亚马逊面试中,**50%的成败在于你能否用故事完美映射LP**。以下精选最常考、最容易挂的5条准则,并提供**STAR-L (Situation, Task, Action, Result, Learning)** 回答模板。

**1. Customer Obsession (客户至上) —— 首席准则**
- **问法:** "Tell me about a time when you had to work on a project with unclear requirements. How did you decide what to build?"
- **算法岗陷阱:** 许多候选人强调模型的精度(AUC +0.1%),亚马逊更看重**对终端客户的延迟影响(P99 Latency)或可用性提升**。
- **标准回答框架:** 我在开发搜索排序模型时发现,提高Transformer层数能提升NDCG@10 2%,但会导致P99延迟增加150ms。通过用户行为分析发现,首页**点击率**才是核心北极星,延迟增加会导致用户流失。最终我设计了基于知识蒸馏的两阶段召回,**牺牲0.5%精度换取50ms延迟下降**,上线后用户停留时长提升3.2%。

**2. Dive Deep (刨根问底) —— 算法岗核心考察点**
- **问法:** "Tell me about the most complex bug or model failure you debugged."
- **必考!** 面试官会就你提到的任何一个技术点向下追问**5层为什么**。例如你说用了Adam优化器,他会问:"为什么不用SGD with Momentum?Batch Size和Learning Rate的线性缩放关系在你们数据集上成立吗?如果不成立,你怀疑是数据分布的哪部分特征导致的?"

**3. Bias for Action (崇尚行动) & Deliver Results (达成业绩)**
- **结合体:** 当数据稀疏时,你是等两周收集数据还是基于先验知识上线一个简单规则模型?
- **标准回答:** 面对新品冷启动无历史点击数据,我无法等待。我利用**多模态CLIP编码器**提取商品图片Embedding计算相似度作为伪标签,配合**Thompson Sampling**进行小流量探索。该方案在2天内上线,CTR初期虽有波动,但**快速验证了该品类的流量天花板**,避免了过度开发。

**4. Invent and Simplify (创新简化)**
- **算法映射:** "Tell me about a time you simplified a complex ML pipeline."
- **示例:** 将原本需要维护的 12 个 XGBoost 小模型(分国家)合并为一个基于 **Deep & Cross Network (DCN)** 的统一模型,利用 Cross Layer 自动学习国家特征交叉,维护成本降低 80%。

### 1.3 Bar Raiser 轮应对策略
Bar Raiser 不关心你是否懂最新论文,只关心你的 **Earn Trust (赢得信任)** 和 **Have Backbone (敢于谏言)**。
- **经典问题:** "Tell me about a time you disagreed with your manager or a senior stakeholder on a technical approach."
- **失败回答:** "最后我听老板的,因为他是老板。"
- **成功回答:** "我反对经理提出的全量上线Transformer模型,因为我跑A/A测试发现Serving开销将增加50%云成本。我花了一周编写**影子流量压力测试脚本**(附有详细Perf数据),并用成本数据说服了经理采纳了两阶段召回方案。虽然我最初的强硬态度让经理不快,但事后季度复盘时他认可了我对成本控制的前瞻性。"

---

## 第二章:算法与编码面试 —— 亚马逊高频题库与多解精析

亚马逊编码面试极其看重**代码风格(OOP/Functional)**、**边界处理**以及 **Follow-up 变通能力**。题目通常不直接给LeetCode原题,而是套上 **"Amazon Locker"** 或 **"Prime Video Recommendation"** 的业务壳子。

### 2.1 数据结构专题:基于业务场景的题目

#### 题目1:设计亚马逊仓库的 Locker 分配系统 (Hard)
**背景:** 仓库有 N 个 Locker,尺寸为 S, M, L。包裹到达时需分配最小且可用的 Locker。包裹离开后 Locker 释放。要求 O(log N) 完成分配与释放。
**考点:** **TreeSet / Ordered Map / 优先队列 的复合使用**

```java
import java.util.*;

/**
 * Amazon Locker 分配系统实现
 * 核心思想:使用 TreeMap 维护可用空间,利用 TreeMap.ceilingEntry() 快速查找 >= 需求的最小尺寸
 */
class LockerSystem {
    // 尺寸枚举
    enum Size {
        SMALL(1), MEDIUM(2), LARGE(3), XLARGE(4);
        int val;
        Size(int val) { this.val = val; }
    }

    // 可用柜子映射: Size -> Count
    private TreeMap<Size, Integer> availableLockers;
    // 包裹ID到分配柜子的映射
    private Map<String, Size> packageAssignment;

    public LockerSystem() {
        // 自定义比较器按Size数值排序
        this.availableLockers = new TreeMap<>((a, b) -> a.val - b.val);
        this.packageAssignment = new HashMap<>();
        // 初始化柜子数量 (假设库存)
        availableLockers.put(Size.SMALL, 100);
        availableLockers.put(Size.MEDIUM, 50);
        availableLockers.put(Size.LARGE, 20);
    }

    /**
     * 分配柜子
     * @param packageId 包裹ID
     * @param requiredSize 最小所需尺寸
     * @return 分配的柜子尺寸,若无合适则返回 null
     */
    public Size allocateLocker(String packageId, Size requiredSize) {
        // ceilingEntry: 返回 >= requiredSize 的最小键值对
        Map.Entry<Size, Integer> entry = availableLockers.ceilingEntry(requiredSize);
        if (entry == null || entry.getValue() == 0) {
            System.out.println("No available locker for package: " + packageId);
            return null;
        }
        
        Size allocated = entry.getKey();
        int count = entry.getValue();
        
        // 更新库存
        if (count == 1) {
            availableLockers.remove(allocated);
        } else {
            availableLockers.put(allocated, count - 1);
        }
        
        packageAssignment.put(packageId, allocated);
        System.out.println("Allocated " + allocated + " locker to " + packageId);
        return allocated;
    }

    /**
     * 释放柜子
     */
    public void releaseLocker(String packageId) {
        Size size = packageAssignment.get(packageId);
        if (size == null) {
            System.out.println("Package not found.");
            return;
        }
        availableLockers.put(size, availableLockers.getOrDefault(size, 0) + 1);
        packageAssignment.remove(packageId);
        System.out.println("Released " + size + " locker from " + packageId);
    }

    public static void main(String[] args) {
        LockerSystem system = new LockerSystem();
        system.allocateLocker("P001", Size.SMALL);  // 分配 SMALL
        system.allocateLocker("P002", Size.LARGE);  // 分配 LARGE
        system.allocateLocker("P003", Size.MEDIUM); // 分配 MEDIUM (只剩MEDIUM没有SMALL?此时SMALL还有99,MEDIUM够)
        system.releaseLocker("P001");               // 释放 SMALL
        system.allocateLocker("P004", Size.SMALL);  // 分配 SMALL (复用释放的)
    }
}
```

#### 题目2:Prime Video 最长连续观看序列 (变种 Longest Consecutive Sequence)
**背景:** 给定用户观看记录的时间戳数组 `[0, 3, 7, 2, 5, 8, 4, 6, 0, 1]`,找出最长连续**自然分钟**序列(允许重复时间戳,重复仅算一次)。
**考点:** 哈希集去重 + 智能遍历

```python
def longest_consecutive_watch(views):
    """
    views: List[int] 观看记录的时间戳 (单位: 分钟)
    返回最长连续自然分钟序列长度
    """
    if not views:
        return 0
        
    nums_set = set(views)
    max_length = 0
    
    for num in nums_set:
        # 只有当 num-1 不在集合中,才认为这是一个序列的起点 (避免 O(N^2) 退化为 O(N))
        if num - 1 not in nums_set:
            current_num = num
            current_streak = 1
            
            while current_num + 1 in nums_set:
                current_num += 1
                current_streak += 1
                
            max_length = max(max_length, current_streak)
            
    return max_length

# 测试
test_views = [0, 3, 7, 2, 5, 8, 4, 6, 0, 1] # 包含 0,1,2,3,4,5,6,7,8 连续9个
print(longest_consecutive_watch(test_views)) # 输出 9
```

### 2.2 算法思想专题:动态规划在物流配送中的应用

#### 题目3:亚马逊无人机配送最优路径 (Amazon Prime Air)
**描述:** 无人机从仓库 (0,0) 出发,需配送 N 个包裹 (x_i, y_i),每到一个点卸货需耗时1单位,移动速度为单位距离1。求最短总时间。最后需返回仓库?*无需返回仓库(亚马逊为节约成本可能让无人机停在某处)*。
**考点:** **旅行商问题 (TSP) 的位掩码 DP (Bitmask DP)**。尽管 N <= 15 是经典范围,面试中通常 N <= 10。

```python
import math

def shortest_drone_time(points):
    """
    points: List[Tuple[int, int]] 包含仓库 (0,0) 作为索引0
    返回最短总时间 (移动时间 + 卸货时间)
    """
    n = len(points)
    # 计算距离矩阵 (欧几里得距离向上取整? 这里直接浮点数保留精度,面试可假设为整数曼哈顿距离)
    dist = [[0.0] * n for _ in range(n)]
    for i in range(n):
        for j in range(n):
            if i != j:
                dx = points[i][0] - points[j][0]
                dy = points[i][1] - points[j][1]
                dist[i][j] = math.hypot(dx, dy)  # sqrt(dx^2 + dy^2)
    
    # DP 数组: dp[mask][i] 表示访问过 mask 集合中的点,且当前停留在点 i 时的最小时间
    # mask 用二进制表示,1 << n
    INF = float('inf')
    dp = [[INF] * n for _ in range(1 << n)]
    dp[1][0] = 0.0  # 初始在点0,mask为1 (仅访问了点0)
    
    for mask in range(1 << n):
        for i in range(n):
            if dp[mask][i] == INF:
                continue
            # 尝试前往未访问的点 j
            for j in range(n):
                if not (mask & (1 << j)):
                    new_mask = mask | (1 << j)
                    # 移动时间 + 卸货时间 (假设每个点卸货耗时 1.0)
                    unloading_time = 1.0 if j != 0 else 0.0 # 仓库无需卸货
                    new_time = dp[mask][i] + dist[i][j] + unloading_time
                    if new_time < dp[new_mask][j]:
                        dp[new_mask][j] = new_time
    
    # 最终结果:访问完所有点 (mask = (1<<n)-1) 且停留在任意点的最小值
    full_mask = (1 << n) - 1
    min_time = min(dp[full_mask][i] for i in range(n))
    return min_time

# 示例: 仓库(0,0), 包裹A(10,0), B(0,10)
points = [(0,0), (10,0), (0,10)]
print(f"最短无人机配送时间: {shortest_drone_time(points):.2f} 单位")
```

### 2.3 系统设计前置:设计一个无锁的并发计数器 (Amazon CloudWatch 场景)
亚马逊面试非常喜欢考察 **并发编程**,尤其是写 **Thread-Safe** 的类。

```java
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * 需求: 海量并发请求计数,要求高性能。
 * 初级方案: synchronized 或 AtomicLong (高并发下CAS自旋浪费CPU)
 * 高级方案: LongAdder (Java 8+) 利用分段累加,降低竞争
 */
public class AmazonRequestCounter {
    // LongAdder 适用于高并发写、低频读的场景 (如QPS统计)
    private final LongAdder counter;
    
    public AmazonRequestCounter() {
        this.counter = new LongAdder();
    }
    
    // 增加计数 (无锁,写操作性能极高)
    public void increment() {
        counter.increment();
    }
    
    // 获取当前总和 (读操作会合并所有Cell,相对较重但准确)
    public long getTotal() {
        return counter.sum();
    }
    
    // 重置 (利用sumThenReset实现原子操作)
    public long sumThenReset() {
        return counter.sumThenReset();
    }
    
    // 演示
    public static void main(String[] args) throws InterruptedException {
        AmazonRequestCounter counter = new AmazonRequestCounter();
        Thread[] threads = new Thread[100];
        for (int i = 0; i < 100; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < 10000; j++) {
                    counter.increment();
                }
            });
            threads[i].start();
        }
        for (Thread t : threads) t.join();
        System.out.println("Total: " + counter.getTotal()); // 1000000
    }
}
```

---

## 第三章:机器学习系统设计 —— 亚马逊搜索与推荐背后的技术栈

这是 Senior 面试的**核心拉分环节**。面试官可能是 Principal Scientist,会给出一个开放问题,例如:"Design YouTube for Amazon Live" 或 "Design a Click-Through Rate prediction system for Sponsored Products"。

### 3.1 经典设计问题:亚马逊搜索广告点击率预估系统

#### 3.1.1 需求澄清 (5分钟)
- **规模:** 每天10亿次查询,QPS峰值 200K。
- **延迟要求:** P99 延迟 < 100ms (包含网络、特征拉取、模型推理、排序)。
- **特征:** 用户历史点击序列、用户画像、搜索词Embedding、广告商品属性、上下文时间。
- **目标:** 最大化 RPM (Revenue Per Mille) 同时兼顾用户体验 (CTR)。

#### 3.1.2 架构总览 (文字讲解 + 示意图描述)
架构分为**离线流**与**在线流**。

**1. 离线训练流 (Offline Training Pipeline)**
- **数据源:** S3 存储的点击日志、曝光日志 (Impression Log)。
- **特征工程 (Spark/EMR):**
    - 用户序列特征:用户过去14天点击/购买的 `Item ID` 序列。使用 `Byte-Pair Encoding (BPE)` 对长序列进行压缩。
    - 多模态特征:商品主图经过预训练的 `ViT` 模型提取 Embedding (512维)。
    - 交叉特征:`User Age Group * Product Category`。
- **模型架构:** **DCN-V2 (Deep & Cross Network v2)** 是亚马逊广告组的常见选择,兼顾了深度记忆与交叉泛化。
- **训练配置:** 使用 TensorFlow / PyTorch 分布式训练 (Parameter Server 或 All-Reduce),使用 **FTRL (Follow The Regularized Leader)** 优化器处理稀疏特征。

**2. 在线推理流 (Online Serving Pipeline)**
- **服务入口:** API Gateway -> 广告检索服务 (Ad Retrieval,基于双塔向量召回) -> **Ranking Service**。
- **Ranking Service 内部组件:**
    - **Feature Store:** 低延迟 KV 存储 (DynamoDB / ElastiCache) 获取用户实时行为。
    - **Model Server:** TensorFlow Serving 或 PyTorch Serve,模型预热、批处理动态组包 (Dynamic Batching) 以提升 GPU 吞吐。
    - **Scoring & Re-ranking:** 计算 pCTR,再乘以 CPC 出价得到 eCPM 排序。

#### 3.1.3 核心代码片段:双塔召回模型的 PyTorch 实现

```python
import torch
import torch.nn as nn
import torch.nn.functional as F

class TwoTowerModel(nn.Module):
    """
    亚马逊搜索广告召回阶段的双塔模型
    User Tower: 编码用户搜索意图和历史行为
    Item Tower: 编码广告商品特征
    """
    def __init__(self, user_feature_dim, item_feature_dim, embedding_dim=64):
        super().__init__()
        self.user_tower = nn.Sequential(
            nn.Linear(user_feature_dim, 256),
            nn.ReLU(),
            nn.Dropout(0.2),
            nn.Linear(256, 128),
            nn.ReLU(),
            nn.Linear(128, embedding_dim)
        )
        
        self.item_tower = nn.Sequential(
            nn.Linear(item_feature_dim, 256),
            nn.ReLU(),
            nn.Dropout(0.2),
            nn.Linear(256, 128),
            nn.ReLU(),
            nn.Linear(128, embedding_dim)
        )
        
        # 温度系数,用于控制Softmax分布的平滑度
        self.temperature = nn.Parameter(torch.tensor(0.07))
        
    def forward(self, user_features, item_features):
        """
        训练时计算 Batch 内 Softmax 交叉熵损失
        user_features: [B, user_feature_dim]
        item_features: [B, item_feature_dim] 正样本
        """
        user_emb = F.normalize(self.user_tower(user_features), p=2, dim=1)  # [B, E]
        item_emb = F.normalize(self.item_tower(item_features), p=2, dim=1)  # [B, E]
        
        # 计算相似度矩阵 [B, B]
        logits = torch.matmul(user_emb, item_emb.T) / self.temperature
        
        # 标签为对角矩阵 (对角线为正样本)
        labels = torch.arange(logits.shape[0], device=logits.device)
        
        # 双向损失: 用户到物品 和 物品到用户
        loss_u2i = F.cross_entropy(logits, labels)
        loss_i2u = F.cross_entropy(logits.T, labels)
        loss = (loss_u2i + loss_i2u) / 2.0
        
        return loss, user_emb, item_emb

    def get_user_embedding(self, user_features):
        """在线服务时用于生成用户向量进行ANN检索"""
        with torch.no_grad():
            user_emb = self.user_tower(user_features)
            return F.normalize(user_emb, p=2, dim=1)

# 模拟训练数据
B = 32
user_feat_dim = 100
item_feat_dim = 50
model = TwoTowerModel(user_feat_dim, item_feat_dim)
dummy_user = torch.randn(B, user_feat_dim)
dummy_item = torch.randn(B, item_feat_dim)
loss, _, _ = model(dummy_user, dummy_item)
print(f"训练损失: {loss.item():.4f}")
```

### 3.2 特定场景优化:处理冷启动问题的贝叶斯个性化排序 (BPR) 代码实现

```python
def bpr_loss(user_emb, pos_item_emb, neg_item_emb):
    """
    贝叶斯个性化排序损失
    用于新品冷启动时强化正负样本区分度
    user_emb: [B, D]
    pos_item_emb: [B, D] 点击/购买商品
    neg_item_emb: [B, D] 曝光未点击商品
    """
    pos_scores = torch.sum(user_emb * pos_item_emb, dim=1)  # [B]
    neg_scores = torch.sum(user_emb * neg_item_emb, dim=1)  # [B]
    
    # BPR 损失: -log(sigmoid(pos - neg))
    loss = -torch.mean(F.logsigmoid(pos_scores - neg_scores))
    return loss
```

### 3.3 面试官追问:如何在线 A/B 测试该算法?

**回答框架 (STAR):**
- **Situation:** 新双塔模型离线 AUC 提升 5%,但需要验证线上业务指标。
- **Task:** 设计分层实验,隔离新模型对搜索无结果率的影响。
- **Action:**
    1. **流量分层:** 使用 `UserId % 100` 取哈希划分 5% 流量到实验组 (Treatment),5% 为对照组 (Control),剩余 90% 保持原状 Holdback。
    2. **指标监控:** 核心指标 RPM (Revenue Per Mille)、CTR、**Search Refinement Rate (二次搜索率)**。护栏指标为 P99 延迟和广告填充率。
    3. **统计检验:** 连续观察 7 天,使用 **CUPED (Controlled-experiment Using Pre-Experiment Data)** 方法利用实验前数据降低方差,加速决策。
- **Result:** 实验组 CTR 提升 2.1% (p-value < 0.01),RPM 提升 1.8%,且延迟无显著增加。灰度放量至 50%。

---

## 第四章:机器学习理论深度 —— 那些你必须钻透的数学细节

亚马逊面试官对 ML 理论的考察极度务实,不会让你背公式,而是考察**直觉与调参经验**。

### 4.1 XGBoost vs LightGBM 在亚马逊稀疏特征场景下的选择

**面试官问:** "我们的 Sponsored Products 数据有 90% 的稀疏类别特征,你会选 XGBoost 还是 LightGBM?为什么?"

**回答解析:**
1. **算法差异:** XGBoost 使用 **Pre-sorted 算法** + 直方图近似,Level-wise 生长。LightGBM 使用 **GOSS (Gradient-based One-Side Sampling)** 和 **EFB (Exclusive Feature Bundling)**,Leaf-wise 生长。
2. **稀疏数据适应性:** LightGBM 对类别特征直接支持 (Categorical Feature Support),无需 One-Hot 编码,这在面对千万级商品ID时**内存占用低一个数量级**。
3. **业务影响:** 如果数据量在 TB 级且特征极度稀疏,LightGBM 训练速度比 XGBoost 快 5-10 倍,且精度几乎无损。但**务必注意过拟合**:Leaf-wise 配合极小叶子节点数需要调整 `min_data_in_leaf` 和 `num_leaves`。

### 4.2 排序指标 NDCG 的代码实现及面试陷阱

**陷阱:** 亚马逊搜索页是**分页展示**的,计算 NDCG 时你是只看第一页还是考虑翻页?如果只看第一页,会导致模型**只讨好头部商品,长尾新品无法曝光**。

```python
import numpy as np

def ndcg_at_k(rel_true, rel_pred, k):
    """
    计算 NDCG@k
    rel_true: 真实相关性列表 (如 [3, 2, 3, 0, 1])
    rel_pred: 模型预测排序后的相关性列表
    """
    def dcg(rel_list):
        # DCG = sum( (2^rel_i - 1) / log2(i+1) )  i从1开始
        rel_array = np.array(rel_list[:k])
        if rel_array.size == 0:
            return 0.0
        gains = 2 ** rel_array - 1
        discounts = np.log2(np.arange(2, rel_array.size + 2))
        return np.sum(gains / discounts)
    
    dcg_max = dcg(sorted(rel_true, reverse=True))  # 理想 DCG
    dcg_pred = dcg(rel_pred)
    
    return dcg_pred / dcg_max if dcg_max > 0 else 0.0

# 示例
true_rel = [3, 2, 3, 0, 1]
pred_rel = [3, 2, 0, 3, 1]  # 将位置3和4调换
print(f"NDCG@5: {ndcg_at_k(true_rel, pred_rel, 5):.4f}")
```

**亚马逊特有考虑:** 建议实现 **Weighted NDCG**,给购买行为赋值 10,加购赋值 5,点击赋值 1。

### 4.3 深度学习模型部署加速:ONNX 与 TensorRT 转换实战 (代码)

面试官可能会问:"如果模型推理延迟超了 10ms 怎么办?"

```python
# 示例: PyTorch -> ONNX -> TensorRT 加速流程
import torch
import torch.onnx

# 1. 假设有一个简单的 Bert 分类头 (用于文本相关性)
class SimpleBertClassifier(torch.nn.Module):
    def __init__(self, bert_model, num_classes):
        super().__init__()
        self.bert = bert_model
        self.classifier = torch.nn.Linear(768, num_classes)
        
    def forward(self, input_ids, attention_mask):
        outputs = self.bert(input_ids, attention_mask=attention_mask)
        pooled = outputs[1]  # pooler output
        return self.classifier(pooled)

# 2. 导出 ONNX (通常需要提供 dummy input)
model = SimpleBertClassifier(...)
model.eval()
dummy_input_ids = torch.randint(0, 30522, (1, 128), dtype=torch.long)
dummy_attention_mask = torch.ones((1, 128), dtype=torch.long)

torch.onnx.export(
    model,
    (dummy_input_ids, dummy_attention_mask),
    "amazon_relevance_model.onnx",
    input_names=["input_ids", "attention_mask"],
    output_names=["logits"],
    dynamic_axes={
        "input_ids": {0: "batch_size", 1: "sequence_length"},
        "attention_mask": {0: "batch_size", 1: "sequence_length"},
        "logits": {0: "batch_size"}
    },
    opset_version=14
)

# 3. (在服务器端) 使用 TensorRT 进行 FP16 量化加速
# 命令: trtexec --onnx=amazon_relevance_model.onnx --fp16 --saveEngine=model_trt.engine
# 推理延迟通常可降至原来的 1/3 到 1/5
```

---

## 第五章:亚马逊供应链与运筹优化 —— 高级算法工程师的另一面

除了推荐搜索,亚马逊的 **SCOT (Supply Chain Optimization Technologies)** 团队极度青睐运筹学与强化学习背景的人才。

### 5.1 库存分配问题:基于线性规划的解决方案

**场景:** 有 M 个仓库,N 种商品。已知各仓库容量、各商品体积、各商品在不同仓库的需求预测。目标是在满足需求的前提下,**最小化跨区调拨的运输成本**。

**数学建模:**
- 决策变量 `x_{i,j}`: 从仓库 i 向区域 j 运输商品的数量。
- 目标函数: `min Σ c_{i,j} * x_{i,j}`。
- 约束: 供应量约束 `Σ_j x_{i,j} <= supply_i`,需求量约束 `Σ_i x_{i,j} >= demand_j`。

```python
from scipy.optimize import linprog

# 示例: 3个仓库 (供应方) -> 4个区域 (需求方)
c = [2, 3, 1, 4,   # 仓库1到区域1-4的成本
     5, 2, 3, 1,   # 仓库2到区域1-4的成本
     3, 4, 2, 5]   # 仓库3到区域1-4的成本

# 供应量约束 (Ax <= b)
# 仓库1供应 <= 50, 仓库2 <= 60, 仓库3 <= 70
A_ub = [[1,1,1,1, 0,0,0,0, 0,0,0,0],  # 仓库1变量之和
        [0,0,0,0, 1,1,1,1, 0,0,0,0],  # 仓库2变量之和
        [0,0,0,0, 0,0,0,0, 1,1,1,1]]  # 仓库3变量之和
b_ub = [50, 60, 70]

# 需求量约束 (Ax >= b) 转化为 -Ax <= -b
# 区域1需求 >= 40, 区域2 >= 30, 区域3 >= 50, 区域4 >= 40
A_eq = None
b_eq = None
# 注意: linprog 处理 A_ub * x <= b_ub。需求 >= 需取负。
A_ub_demand = [
    [-1,0,0,0, -1,0,0,0, -1,0,0,0],  # 区域1变量取负和
    [0,-1,0,0, 0,-1,0,0, 0,-1,0,0],  # 区域2
    [0,0,-1,0, 0,0,-1,0, 0,0,-1,0],  # 区域3
    [0,0,0,-1, 0,0,0,-1, 0,0,0,-1]   # 区域4
]
b_ub_demand = [-40, -30, -50, -40]

# 合并所有不等式约束
A_ub_total = A_ub + A_ub_demand
b_ub_total = b_ub + b_ub_demand

# 变量边界 (非负)
bounds = [(0, None)] * 12

res = linprog(c, A_ub=A_ub_total, b_ub=b_ub_total, bounds=bounds, method='highs')

if res.success:
    print(f"最优运输成本: {res.fun:.2f}")
    allocations = res.x.reshape(3, 4)
    print("分配矩阵 (仓库 x 区域):\n", allocations)
else:
    print("无可行解")
```

### 5.2 动态定价的强化学习建模 (Q-Learning 代码)

亚马逊会根据库存水平和竞争对手价格动态调价。**面试题:** 设计一个简单的 Q-Learning 模型来决定提价还是降价。

```python
import numpy as np

class AmazonPricingEnv:
    """
    简化版定价环境
    状态: (库存水平[0-100], 价格水平[1-5])
    动作: 0=降价1档, 1=维持, 2=提价1档
    奖励: 销量 * 利润 - 库存持有成本
    """
    def __init__(self):
        self.inventory = 50
        self.price_level = 3  # 1-5
        self.max_steps = 100
        
    def step(self, action):
        # 动作执行
        if action == 0: self.price_level = max(1, self.price_level - 1)
        elif action == 2: self.price_level = min(5, self.price_level + 1)
        
        # 需求模拟: 价格低需求大,库存不足时需求流失
        demand = int((6 - self.price_level) * np.random.uniform(8, 12))
        sales = min(demand, self.inventory)
        self.inventory -= sales
        
        # 奖励: 假设成本为2,基础价格 level * 10
        revenue = sales * (self.price_level * 10)
        cost = sales * 2
        holding_cost = self.inventory * 0.5
        reward = revenue - cost - holding_cost
        
        done = self.inventory <= 0
        next_state = (self.inventory, self.price_level)
        return next_state, reward, done

# Q-Learning 训练
env = AmazonPricingEnv()
q_table = np.zeros((101, 6, 3))  # 库存0-100,价格1-5,动作3
alpha, gamma, epsilon = 0.1, 0.95, 0.1

for episode in range(1000):
    env = AmazonPricingEnv()
    inv, price = env.inventory, env.price_level
    done = False
    while not done:
        if np.random.random() < epsilon:
            action = np.random.randint(3)
        else:
            action = np.argmax(q_table[inv, price])
            
        (next_inv, next_price), reward, done = env.step(action)
        
        # Q-Learning 更新
        old_value = q_table[inv, price, action]
        next_max = np.max(q_table[next_inv, next_price])
        new_value = (1 - alpha) * old_value + alpha * (reward + gamma * next_max)
        q_table[inv, price, action] = new_value
        
        inv, price = next_inv, next_price

print("训练完成,最优策略示例 (库存50,价格等级3):")
best_action = np.argmax(q_table[50, 3])
action_map = {0: "降价", 1: "维持", 2: "提价"}
print(f"建议动作: {action_map[best_action]}")
```

---

## 第六章:面试后的博弈 —— 薪资谈判与 Offer 选择

### 6.1 亚马逊薪资结构解析 (L6 Senior Applied Scientist)
- **Base:** $160k - $200k (视地点而定,西雅图 vs 湾区)
- **Sign-on Bonus:** Year 1: $80k - $120k (分月发放),Year 2: $60k - $90k。
- **RSU (限制性股票):** 4年总包 $300k - $600k。**注意:** 亚马逊股票是 **5/15/40/40** 后置式发放(前两年极少),这是谈判关键。
- **总包 TC 范围:** $300k - $450k。

### 6.2 谈判话术技巧 (利用 Bar Raiser 后的唯一窗口)
当你拿到口头 Offer 后,**Recruiter 是你的盟友**,因为他们的 KPI 是入职率。
- **标准说辞:** "I'm extremely excited about the team's vision on XXX. However, I have another offer from Google Cloud with a more front-loaded equity structure. Is there any flexibility on the Year 1 cash sign-on to bridge the gap?"
- **禁忌:** 千万不要用 "I need more money",要用 **"Align with market data"**。

### 6.3 最终决策:亚马逊的 Offer 值不值得接?
**优点:**
- 无与伦比的**工程与业务结合**的规模感。
- 内部流动性强 (换组相对容易)。
- 简历上的金字招牌。
**缺点:**
- **PIP Culture:** 虽然算法岗相对安全,但 URA (Unregretted Attrition) 指标依然存在。
- **Oncall 压力:** 高级算法工程师也需要参与 Production 系统 Oncall。

---

## 第七章:附录 —— 100+ 道亚马逊算法岗真题速查表

| 类别 | 题目 | 亚马逊变种提示 |
| :--- | :--- | :--- |
| **Array** | Two Sum | 找三个数使和为 Prime Video 观看时长 |
| **String** | Longest Palindrome | 找最长回文商品名 |
| **Tree** | LCA of BST | 找 Organizational Chart 最近共同经理 (Manager Chain) |
| **Graph** | Course Schedule | 部署服务依赖拓扑排序 (AWS Lambda 冷启动) |
| **DP** | Knapsack | 有限体积纸箱装最多价值商品 |
| **ML** | XGBoost 分裂准则推导 | 要求手写二阶泰勒展开 |
| **ML** | Batch Norm 训练/测试差异 | 要求推导 Running Mean 更新公式 |
| **System** | 设计 Uber 估价系统 | 设计 Amazon Flex 配送费预估 |

---

## 结语:拥抱“Day 1”心态

亚马逊面试不仅是对技术的检验,更是对**心智成熟度**的筛选。你可能会遇到打断你思路的面试官(模拟真实会议场景),也可能遇到全程一言不发的冷面考官。记住:**保持冷静,用数据说话,始终将客户体验放在第一位**。当你成功跨越这道门槛,你会发现亚马逊的算法世界深邃而迷人。

**推荐延伸阅读(CSDN 优质博文):**
- [CSDN: 亚马逊算法面试最新面经与高频题总结](https://blog.csdn.net/2511_93835513/article/details/159249744?spm=1001.2014.3001.5502)

*Good luck with your Amazon loop!*

更多推荐