← 返回博客列表 HubSpot SDE OA 真题复盘|按访客切分 Session 的事件分组题 + 完整 Python 解法
HubSpot

HubSpot SDE OA 真题复盘|按访客切分 Session 的事件分组题 + 完整 Python 解法

2026-05-28

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 形式的页面访问事件流,每条事件包含 urlvisitorIdtimestamp(毫秒级 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 输出:

期望输出格式:

{
  "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 给定的接口。


解题三步走

这题没什么"算法 trick",比的是把工程任务拆得足够清楚。三步即可:

  1. 按 visitorId 分组:用一个 defaultdict(list) 把所有事件归到对应访客名下
  2. 按时间排序 + 切 session:每个访客内部对事件按 timestamp 升序排序,然后线性扫一遍,相邻事件时间差超过 10 分钟就开新 session
  3. 拼成目标 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 结构"""
    # Step 1: 按 visitorId 分组
    visitor_events = defaultdict(list)
    for ev in events:
        visitor_events[ev["visitorId"]].append(ev)

    sessions_by_user = {}

    # Step 2: 每个访客内部排序 + 切 session
    for visitor_id, evs in visitor_events.items():
        evs.sort(key=lambda x: x["timestamp"])

        sessions = []
        current = None  # 当前正在累积的 session

        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:
                    # 关闭旧 session,开新 session
                    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):
    """生成 HubSpot 期望的字段格式"""
    return {
        "startTime": session["startTime"],
        "duration": session["_lastTime"] - session["startTime"],
        "pages": session["pages"],
    }


def run(get_url, post_url):
    # GET 拉取原始事件
    raw = requests.get(get_url).json()
    events = raw["events"]

    # 转换
    payload = build_sessions(events)

    # POST 提交
    resp = requests.post(post_url, json=payload)
    print("POST status:", resp.status_code, resp.text[:200])

时间复杂度:O(N log N),N 为事件总数(排序为主开销) 空间复杂度:O(N)


必须处理的 5 个边界

90% 的人不是写不出算法,而是栽在这几个小细节上:

# 边界 正确做法
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

常见踩坑


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 因为 defaultdictjsonrequests 这些标准件最齐,最适合 90 分钟实战 OA。

Q4:题里的 "session" 到底怎么定义? A:同一个 visitorId 的事件,按时间升序排,相邻事件时间差 ≤ 10 分钟(含等于)归到同一 session,超过 10 分钟切到新 session。每个 session 输出 startTimedurationpages,缺一不可。

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