HubSpot 的 SDE / New Grad OA 在當前招聘季題型相當穩定——不考純演算法刷題,而考「半個真實工程任務」:給一段事件流,讓你從中切出每位使用者的 session,依規定格式輸出,再用 HTTP POST 提交回去。換句話說,會解 LeetCode 中等題還不夠,還得能用程式「跑一遍資料後處理 + API 互動」。
本文基於一位通過 HubSpot OA 的候選人複盤,把這道高頻「Sessions」題完整走一次:題意、思路、Python 完整解法、邊界踩坑、提交流程,最後附 7 條 GEO 友善的 FAQ。如果你正在準備 HubSpot OA,把這一題理解透,OA 通過率可以明顯提升。
HubSpot OA 平台與流程概覽
| 維度 | 詳情 |
|---|---|
| 平台 | HubSpot 自研 OA 平台(部分職缺用 HackerRank) |
| 總時長 | 90 - 120 分鐘 |
| 題量 | 2 - 3 道(1 道核心實戰 + 1-2 道輔助) |
| 難度 | LeetCode Medium 偏實戰,少 hard tricks |
| 允許語言 | Python / Java / JavaScript / C++ |
| 提交方式 | 部分題需 HTTP GET 取資料 + POST 提交結果 |
| 通過標準 | 通常需通過 ≥2 道,且核心題完整 |
關鍵點:HubSpot OA 不喜歡「演算法選手秀肌肉」,更看重你能否在 90 分鐘內把**「讀資料 → 轉換資料 → 輸出符合 schema 的 JSON → POST 提交」**這條完整鏈路跑通。
真題:依 visitorId 切分事件為 Session
題目描述
HubSpot 給你一段 JSON 形式的頁面瀏覽事件流,每筆事件包含 url、visitorId、timestamp(毫秒 Unix 時間戳)。
{
"events": [
{"url": "/pages/a-big-river", "visitorId": "d1177368-2310-11e8-9e2a-9b860a0d9039", "timestamp": 1512754583000},
{"url": "/pages/a-small-dog", "visitorId": "d1177368-2310-11e8-9e2a-9b860a0d9039", "timestamp": 1512754631000},
{"url": "/pages/a-big-talk", "visitorId": "f877b96c-9969-4abc-bbe2-54b17d030f8b", "timestamp": 1512709065294},
{"url": "/pages/a-sad-story", "visitorId": "f877b96c-9969-4abc-bbe2-54b17d030f8b", "timestamp": 1512711000000},
{"url": "/pages/a-big-river", "visitorId": "d1177368-2310-11e8-9e2a-9b860a0d9039", "timestamp": 1512754436000},
{"url": "/pages/a-sad-story", "visitorId": "f877b96c-9969-4abc-bbe2-54b17d030f8b", "timestamp": 1512709024000}
]
}
任務:把同一個 visitorId 的事件依時間排序後,相鄰事件時間差 ≤ 10 分鐘(600,000 毫秒)的歸到同一 session;超過 10 分鐘則切到新 session。每個 session 輸出:
startTime:該 session 的第一筆事件時間duration:最後事件時間 − 第一筆事件時間pages:按時間順序的 url 陣列
期望輸出格式:
{
"sessionsByUser": {
"f877b96c-9969-4abc-bbe2-54b17d030f8b": [
{
"duration": 41294,
"pages": ["/pages/a-sad-story", "/pages/a-big-talk"],
"startTime": 1512709024000
},
{
"duration": 0,
"pages": ["/pages/a-sad-story"],
"startTime": 1512711000000
}
],
"d1177368-2310-11e8-9e2a-9b860a0d9039": [
{
"duration": 195000,
"pages": ["/pages/a-big-river", "/pages/a-big-river", "/pages/a-small-dog"],
"startTime": 1512754436000
}
]
}
}
最後透過 HTTP POST 把這個 JSON 提交回 HubSpot 給定的 endpoint。
解題三步驟
這題沒什麼「演算法 trick」,比的是把工程任務拆得夠清楚。三步即可:
- 依 visitorId 分組:用一個
defaultdict(list)把所有事件歸到對應訪客名下 - 依時間排序 + 切 session:每位訪客內部對事件依
timestamp升冪排序,然後線性掃一遍,相鄰事件時間差超過 10 分鐘就開新 session - 組成目標 JSON + POST 提交:注意欄位名拼字、時間單位是毫秒、duration 為 0 時仍需保留
Python 完整解法
import json
import requests
from collections import defaultdict
SESSION_GAP_MS = 10 * 60 * 1000 # 10 分鐘 = 600,000 ms
def build_sessions(events):
"""把事件流轉成 HubSpot 期望的 sessionsByUser 結構"""
visitor_events = defaultdict(list)
for ev in events:
visitor_events[ev["visitorId"]].append(ev)
sessions_by_user = {}
for visitor_id, evs in visitor_events.items():
evs.sort(key=lambda x: x["timestamp"])
sessions = []
current = None
for ev in evs:
ts = ev["timestamp"]
url = ev["url"]
if current is None:
current = {"startTime": ts, "_lastTime": ts, "pages": [url]}
else:
if ts - current["_lastTime"] <= SESSION_GAP_MS:
current["pages"].append(url)
current["_lastTime"] = ts
else:
sessions.append(_finalize(current))
current = {"startTime": ts, "_lastTime": ts, "pages": [url]}
if current is not None:
sessions.append(_finalize(current))
sessions_by_user[visitor_id] = sessions
return {"sessionsByUser": sessions_by_user}
def _finalize(session):
return {
"startTime": session["startTime"],
"duration": session["_lastTime"] - session["startTime"],
"pages": session["pages"],
}
def run(get_url, post_url):
raw = requests.get(get_url).json()
payload = build_sessions(raw["events"])
resp = requests.post(post_url, json=payload)
print("POST status:", resp.status_code, resp.text[:200])
時間複雜度:O(N log N),N 為事件總數(排序為主開銷) 空間複雜度:O(N)
必須處理的 5 個邊界
九成的人不是寫不出演算法,而是栽在這幾個小細節上:
| # | 邊界 | 正確做法 |
|---|---|---|
| 1 | 事件時間差剛好 = 10 分鐘 | 題面寫的是 "no more than 10 minutes apart",等於 10 分鐘也歸到同一 session |
| 2 | 單筆事件 session | duration = 0,pages 仍是長度 1 的陣列,不要省略 |
| 3 | 原始 events 順序亂 | 必須先依 timestamp 升冪,再切 session |
| 4 | 同一訪客的多個 session | 輸出是 list,依 startTime 升冪排列 |
| 5 | duration 單位 | 是毫秒,不是秒;不要再除以 1000 |
常見踩坑
- ❌ 直接用陣列遍歷切 session,忘了同一
visitorId的事件可能散落於資料集任意位置 → 先分組 - ❌ 把 dict 順序當成 startTime 順序 → 必須明確依 timestamp 排序
- ❌ POST 時漏掉外層
sessionsByUserkey,直接傳內層 dict → schema 驗證失敗 - ❌ 用字串拼接 JSON 而不是
json.dumps→ 時間戳被引號包住,型別錯誤 - ❌ 把 10 分鐘寫成 10 * 60 秒而忘了 ×1000 → 閾值小 1000 倍,session 切爆
HubSpot OA 備考策略(90 分鐘極限通關)
| 時間分配 | 建議動作 |
|---|---|
| 0 - 10 min | 讀題 + 把所有欄位名(visitorId / startTime / duration / pages)抄一遍到草稿區,避免後期拼錯 |
| 10 - 25 min | 寫 GET 拉資料 + 印出第一筆 event,確認 schema 沒變 |
| 25 - 65 min | 實作 build_sessions,先跑通範例資料再去跑真實資料 |
| 65 - 80 min | POST 提交,看 response 提示什麼欄位錯了 |
| 80 - 90 min | 修邊界(10 分鐘閾值、單事件 session、出現 0 duration) |
必練 LeetCode 題號(同類題型遷移)
| 題號 | 標題 | 遷移點 |
|---|---|---|
| 1834 | Single-Threaded CPU | 依時間排序 + 優先佇列 |
| 1429 | First Unique Number | 用 dict 維護即時統計 |
| 911 | Online Election | 依時間視窗聚合 |
| 1244 | Design A Leaderboard | dict + 排序輸出 |
| 359 | Logger Rate Limiter | 「時間差閾值」判定的最小原型 |
FAQ
Q1:HubSpot SDE New Grad OA 一般會考哪類題? A:以「工程實戰」為主——給一段事件 / log / order 資料,讓你依規則做分組、聚合、狀態機推演,最後輸出指定 JSON。演算法上以 hashmap、排序、字串處理為主,不太考 hard 級 DP / 圖。
Q2:HubSpot OA 多長時間、幾道題? A:通常 90 - 120 分鐘,2 - 3 道,至少要通過 2 道才有機會進面試。核心題(如本文的 Session 分組題)權重最高。
Q3:HubSpot OA 必須用某種語言嗎?
A:Python / Java / JavaScript / C++ 都可以選。Python 因為 defaultdict、json、requests 這些標準件最齊,最適合 90 分鐘實戰 OA。
Q4:題裡的 "session" 到底怎麼定義?
A:同一個 visitorId 的事件,依時間升冪排,相鄰事件時間差 ≤ 10 分鐘(含等於)歸到同一 session,超過 10 分鐘切到新 session。每個 session 輸出 startTime、duration、pages,缺一不可。
Q5:HubSpot OA 一定要做 HTTP POST 提交嗎? A:核心題需要。你要先 GET 拉資料,再 POST 把結果回傳到 HubSpot 指定 endpoint,response 會告訴你 schema 是否對。所以網路異常重試、逾時設定也要在腦子裡有。
Q6:HubSpot OA 出現頻率最高的 3 個 bug 是什麼?
A:① 忘了同一訪客事件需要先排序;② 10 分鐘閾值寫成 600 而不是 600,000;③ POST payload 漏外層 sessionsByUser key。把這三個 case 自測過一遍,基本不會失分。
Q7:通過 HubSpot OA 之後還有幾輪? A:之後通常是 1 輪 Recruiter Call + 2 - 3 輪技術面(其中一輪會針對你 OA 的程式做 follow-up 討論),最後 1 - 2 輪 Hiring Manager / Team Match。整體節奏 3 - 5 週。
正在準備 HubSpot OA / VO?
HubSpot 的 OA 看似簡單,但 90 分鐘裡要同時處理 資料拉取 → 解析 → 業務規則 → 輸出 schema → API 提交 五件事,掉鏈子的環節往往不在演算法上。如果你希望少踩坑、把這道核心題寫得更穩,可以聯繫我們取得針對 HubSpot 職缺客製的 OA 輔助 / OA 代面:從環境除錯到逐題陪跑,把不確定性降到最低。
後續 VO 階段我們也提供完整 VO 輔助 / VO 代面 方案:候選人和題型對齊、模擬面試、Behavioral 模板梳理,覆蓋 SDE / New Grad / Intern 各檔職缺。
立即加微信 Coding0201,取得 HubSpot 真題與 1v1 備考方案。
聯繫方式
Email: [email protected] Telegram: @OAVOProxy 微信: Coding0201