My Pinterest onsite ran four rounds: a behavioral round, two coding problems, and two system design questions. The pace was packed, and it ended in an offer. This debrief lays out the real questions, my approach, and the code for each round. If you're prepping for a Pinterest onsite too, I hope this note helps you zero in on what each round is really testing. If you're looking for VO interview assist or VO live support, the contact details at the end are for you.
Environment and Format Overview
All four rounds ran over video. Coding used a shared live editor; system design was drawn and explained on a whiteboard tool. The overall feel: the behavioral round cares a lot about whether you can explain a tradeoff with data, the coding rounds lean toward "step-by-step evolution plus edge-case clarification," and the system design rounds care most about whether you confirm requirements before you start designing.
| Round | Format | Focus |
|---|---|---|
| Round 1 · BQ | Behavioral + probing | STAR structure, simplifying a complex system, UX vs. business-metric tradeoffs |
| Round 2 · Coding | Live coding + explanation | Piece reachability on a board, three-step evolution, direction map + obstacle HashSet |
| Round 3 · System Design | Whiteboard + explanation | Streaming join + group-by dashboard, bulk catalog upload architecture |
| Round 4 · Coding | Live coding + explanation | Itinerary reconstruction from shuffled tickets, Map + Set to find the start |
Pacing tip: in the coding rounds, clarify thoroughly before you write; in system design, never jump straight to picking a database. Confirm the read/write pattern first, then decide on the design.
Round 1: BQ Behavioral
Questions
This round had two questions:
- Tell me about a time you made a complex system simple.
- When user experience and business metrics conflict, how do you make the tradeoff?
My Answer (STAR)
For the first question I used my experience optimizing a recommendation-feed dedup service.
- Situation: The dedup service for the recommendation feed was responsible for filtering out duplicate content. As traffic grew, both the latency of the dedup API and the system load kept climbing, and it became a bottleneck in the pipeline.
- Task: I needed to bring down the API latency and system load without sacrificing dedup accuracy.
- Action: I reworked the service architecture, turning the serial multi-query pattern within a single request into a per-dimension layered flow, and introduced a caching strategy for hot keys so that high-frequency duplicate content gets intercepted at the cache layer, reducing pass-through to the underlying store.
- Result: After the change, both API latency and system load dropped noticeably. I had prepared before/after data comparison charts, and the interviewer liked this "let the data speak" approach, then followed up along the charts to probe several tradeoff details.
For the second question I emphasized: when UX and business metrics conflict, first quantify the impact on both sides, then consider whether the decision is short-term or long-term. For example, a change might lift clicks in the short term but hurt long-term retention. I would use layered A/B metrics to put "short-term gain" and "long-term experience cost" side by side, then decide the tradeoff point together with product, rather than fixating on a single metric.
Takeaway
The biggest plus in a behavioral round is grounding the abstract "I optimized a system" in concrete numbers. Prepare before/after comparison charts so you have something to lean on when they probe the tradeoffs.
Round 2: Coding -- Piece Reachability
The interviewer had a strong accent, but communication was completely fine. The problem evolved in three steps.
Step 1: Queen Only
Given a start position and board size, a Queen can move along up/down, left/right, and the four diagonals, eight directions in total. Add every in-bounds position it can reach.
Step 2: Add Obstacles
Use a HashSet of obstacle coordinates. When scanning a direction, stop immediately on hitting an obstacle: the Queen can neither land on it nor pass through it.
Step 3: Support Multiple Piece Types
Support different pieces via a piece_type parameter: a Queen uses 8 directions, a Bishop only the 4 diagonals, and a Rook only up/down/left/right. The bounds check, obstacle check, and direction scan all share one code path; only the direction map differs.
Python Solution
from typing import List, Set, Tuple
# Direction map per piece type
DIRECTIONS = {
"queen": [(-1, 0), (1, 0), (0, -1), (0, 1),
(-1, -1), (-1, 1), (1, -1), (1, 1)],
"bishop": [(-1, -1), (-1, 1), (1, -1), (1, 1)],
"rook": [(-1, 0), (1, 0), (0, -1), (0, 1)],
}
def reachable_positions(
start: Tuple[int, int],
n: int,
piece_type: str,
obstacles: Set[Tuple[int, int]],
) -> List[Tuple[int, int]]:
"""Compute all positions the piece can reach from start on an n x n board.
Step along each direction for the piece until we go out of bounds
or hit an obstacle.
"""
directions = DIRECTIONS[piece_type]
result: List[Tuple[int, int]] = []
r0, c0 = start
for dr, dc in directions:
r, c = r0 + dr, c0 + dc
# Keep walking this direction until out of bounds or an obstacle
while 0 <= r < n and 0 <= c < n:
if (r, c) in obstacles:
break # cannot land on or pass through an obstacle
result.append((r, c))
r += dr
c += dc
return result
Time complexity: O(n + b), where n is the board side length (each direction walks at most n steps, and the number of directions is constant) and b is the obstacle count (cost of building the HashSet). Space complexity: O(b) for the obstacle set.
Takeaway
The key to the three-step evolution is letting the obstacle check and direction scan share one path: adding obstacles only adds a break inside the while, and adding piece types only swaps the direction map, leaving the core logic untouched. The interviewer valued this "add requirements without tearing down the structure" style.
Round 3: System Design -- Two Design Questions
Design 1: Ad-Event Aggregation Dashboard
Two existing services emit ad events (adId, servingId) and user events (servingId, action type click / impression, region). Build a dashboard that aggregates by ad, action type, and region.
At its core this is a streaming join + group-by aggregation: ad events build a servingId -> adId mapping, user events enrich via servingId to attach the adId, then aggregate by (adId, action, region).
Architecture choices:
- Kafka ingests both event streams.
- Flink does the streaming join and windowed aggregation: one path consumes ad events to maintain the mapping, another consumes user events to enrich, then aggregates over windows by dimension.
- Redis holds the short-lived
servingId -> adIdmapping (ad events typically arrive before user events, so the mapping only needs to live briefly). - Aggregated results go to an OLAP store (such as a columnar analytics database) for the dashboard's multi-dimensional queries.
Points to raise proactively: how to set the TTL for the servingId mapping, how to handle out-of-order / late events with watermarks, and whether the aggregation uses tumbling or sliding windows.
Design 2: Bulk Catalog Upload
Merchants bulk-upload catalogs (price, inventory, etc.), with up to 500k products per job.
My initial idea was to have the client / SDK split the data into batches of 100 rows and push them up, but I quickly realized this pushes reliability and job management onto the client, which is not ideal.
A better approach:
- The merchant uploads the large file directly to object storage, and the server returns a job ID.
- A message queue asynchronously drives parsing, validation, sharding, and bulk writes.
- The client polls progress and failure details by job ID, and only needs to retry the failed parts.
This way the client only handles the upload and polling, the heavy lifting happens asynchronously on the server, and both reliability and observability improve.
Lesson learned: don't pick a write-optimized database before confirming the read pattern. First confirm the catalog's read frequency, query patterns, update ratio, and consistency needs, then decide how to configure the database / indexes / cache.
Round 4: Coding -- Itinerary Reconstruction
Given a set of shuffled tickets, each with an origin and a destination, all forming exactly one complete route, reconstruct the correct itinerary order.
Approach
Use an origin -> destination Map and a Set of all destinations. The origin that does not appear in the destination set is the start of the whole route. Then follow the map station by station.
Python Solution
from typing import Dict, List, Set, Tuple
def reconstruct_itinerary(
tickets: List[Tuple[str, str]]
) -> List[str]:
"""Reconstruct the full itinerary from shuffled tickets.
Build an origin -> destination map, find the unique start,
then follow the map station by station to build the route.
"""
next_stop: Dict[str, str] = {}
destinations: Set[str] = set()
for origin, dest in tickets:
next_stop[origin] = dest
destinations.add(dest)
# Find the start: the origin that never appears as a destination
start = None
for origin, _ in tickets:
if origin not in destinations:
start = origin
break
# Follow the map station by station to build the itinerary
itinerary = [start]
current = start
while current in next_stop:
current = next_stop[current]
itinerary.append(current)
return itinerary
Time complexity: O(n), where n is the number of tickets (one pass to build the map, one pass to walk it). Space complexity: O(n) for the map and destination set.
Follow-up: Edge Cases
The interviewer probed several abnormal inputs:
- Duplicate origins: the same origin on multiple tickets makes
origin -> destinationoverwrite itself, so the route is no longer unique. - Cyclic routes: the route loops back on itself, there is no "origin not in the destination set," and the
whilecan loop forever. - Multiple disconnected routes: there are several starts, and they can't chain into one route.
- Unused tickets: some tickets go unused, and the reconstructed itinerary is shorter than expected.
My handling was to clarify with the interviewer first: does the input guarantee a single, valid, unique chain? Once the convention is confirmed, decide accordingly. If it's not guaranteed, detect the anomaly (for example, number of starts != 1, or reconstructed station count != ticket count + 1) and, by the agreed convention, return an error, return empty, or report the specific anomaly, rather than silently emitting a wrong route.
Prep Notes
- Let data speak in BQ: ground "I optimized a system" in before/after numbers, and plan ahead for how you'll answer when they probe the tradeoffs.
- Coding evolves in steps: Pinterest's coding problems often add requirements one step at a time, so leave extension points for "add obstacles, add types" as you write, avoiding a full rewrite.
- Clarify before choosing in system design: confirm the read/write pattern, data volume, and consistency needs first, then talk databases, caches, and indexes. Don't jump straight to a write-optimized store.
- Clarify edge cases proactively: for problems like itinerary reconstruction, whether the input is a single valid chain directly decides the solution, so ask up front before you start.
FAQ
Q1: How many rounds is a Pinterest VO, and what does it cover?
Mine was four rounds: one behavioral round, two coding rounds, and one system design round (with two design questions). The behavioral round tests tradeoff articulation, coding leans toward step-by-step evolution, and system design checks whether you confirm requirements first.
Q2: Why do the coding problems favor a "three-step" format?
They want to see whether you can keep your structure from collapsing as requirements grow. The piece problem went from Queen to obstacles to multiple piece types; the good approach shares one direction-scan path, so adding requirements only swaps the direction map and adds a break.
Q3: For the ad-event aggregation dashboard, why Flink instead of batch processing?
The dashboard needs near-real-time multi-dimensional aggregation, and events flow in continuously. Flink handles the streaming join and windowed aggregation, paired with Kafka for ingestion, Redis for the short-lived mapping, and an OLAP store for the aggregated results, keeping the whole pipeline real-time.
Q4: For bulk catalog upload, why not have the client split into batches?
Client-side batching pushes retries, progress management, and failure recovery onto the client, which hurts reliability. A better approach is to upload the large file to object storage to get a job ID, then have the server asynchronously parse, validate, shard, and bulk-write via a message queue, with the client only polling progress and failure details.
Q5: What about duplicate origins or cycles in itinerary reconstruction?
Confirm with the interviewer first whether the input guarantees a single valid chain. If it's not guaranteed, detect the anomaly: number of starts other than 1, or a mismatch between reconstructed station count and ticket count, and by the agreed convention return an error, return empty, or report the anomaly, rather than silently emitting a wrong route.
Prepping for a Pinterest VO? We know the rhythm of the four rounds -- data-driven tradeoffs in BQ, step-by-step evolution in coding, requirement clarification in system design -- and offer VO interview assist and VO live support from mock runs to the real thing, helping you polish every round.
Add WeChat Coding0201 now to get a one-on-one custom prep plan.
Contact
- WeChat: Coding0201
- Email: [email protected]
- Telegram: @OAVOProxy