Pinterest interviews have a reputation for being brutal, but in practice they are reasonable—the problems are not tricky, yet they put heavy weight on code quality, communication clarity, and ownership. The full Virtual Onsite is three coding rounds plus one Hiring Manager conversation. Coding does not chase clever tricks; it checks whether you can write robust, extensible, production-flavored code. Here is a full debrief of the three real problems, each with a representative pattern.
Pinterest SDE VO at a Glance
| Dimension | Details |
|---|---|
| Rounds | 3 coding + 1 HM competency |
| Format | Remote video, heavy verbal reasoning |
| Difficulty | Medium; problems aren't obscure, but follow-ups go deep |
| Focus | Graphs / state management / data-access interface design |
| Style | Engineering-flavored; coding often embeds design elements |
Key reminder: most Pinterest problems connect to real system design, so variable naming, boundary handling, and extensibility are scoring drivers. There is no standalone system design round, but coding rounds routinely smuggle in design elements—come ready to discuss trade-offs in depth.
Problem 1: Reachability With at Most K Switch Flips (Variant BFS)
Given a city map where each edge is a one-way road with a switch (on/off), determine whether a path exists from city A to city B if you may flip at most K switches to make roads passable.
Reframe: a classic shortest-path state is "current node." Here we expand the state to (current node, flips used so far). Each time you hit a closed road, if you still have flip budget, spend one and enqueue; an open road costs nothing. Deduplicate on visited[node][flips] so the same node reached with a different flip count stays a distinct state.
from collections import deque
def can_reach(n, edges, A, B, K):
# edges[u] = list of (v, is_open); is_open=True means the road is already passable
graph = [[] for _ in range(n)]
for u, v, is_open in edges:
graph[u].append((v, is_open))
start = (A, 0) # state = (node, flips used)
visited = {start}
q = deque([start])
while q:
node, flips = q.popleft()
if node == B:
return True
for nxt, is_open in graph[node]:
cost = 0 if is_open else 1
nf = flips + cost
if nf <= K and (nxt, nf) not in visited:
visited.add((nxt, nf))
q.append((nxt, nf))
return False
Key point: the interviewer cared most about whether the flip-count logic avoids redundant visits—a node reached with different flip counts is a different state, so deduplicating on the node alone would miss solutions or loop forever. Time: O((V+E)·K). Space: O(V·K).
Problem 2: LRU Cache With an Eviction Callback
Beyond standard
get/put, support firing a callback whenever an element is evicted because the cache hit its capacity limit.
Reframe: the backing structure is still a doubly linked list + hash map. The twist is the eviction moment—only when put overflows capacity and the tail node is dropped do we invoke the callback, and we invoke it after removal so the callback observes a consistent state.
class Node:
__slots__ = ("key", "val", "prev", "next")
def __init__(self, key=0, val=0):
self.key, self.val = key, val
self.prev = self.next = None
class LRUCacheWithEviction:
def __init__(self, capacity, on_evict=None):
self.cap = capacity
self.on_evict = on_evict # eviction callback
self.cache = {}
self.head, self.tail = Node(), Node()
self.head.next, self.tail.prev = self.tail, self.head
def _remove(self, node):
node.prev.next, node.next.prev = node.next, node.prev
def _add_front(self, node):
node.prev, node.next = self.head, self.head.next
self.head.next.prev = node
self.head.next = node
def get(self, key):
if key not in self.cache:
return -1
node = self.cache[key]
self._remove(node)
self._add_front(node)
return node.val
def put(self, key, val):
if self.cap <= 0:
return
if key in self.cache:
self._remove(self.cache[key])
node = Node(key, val)
self.cache[key] = node
self._add_front(node)
if len(self.cache) > self.cap:
lru = self.tail.prev
self._remove(lru)
del self.cache[lru.key]
if self.on_evict: # callback fires after removal
self.on_evict(lru.key, lru.val)
After I finished, the interviewer pushed on thread safety (unexpected in an algorithm round): do you need a lock, do you support concurrent access, and "what if the callback runs too long and stalls the main flow?" I noted you could push the callback onto an async queue so it never blocks put. Time: amortized O(1) for both get and put.
Problem 3: Log-Access Query Class Design
Input is log-access records
(user_id, action_type, timestamp). Implement a class with two methods:countUniqueUsers(start, end)returns distinct users in the time window;getUserActions(user_id, start, end)returns all actions for a user in the window.
Reframe: a classic "index structure + range query" design problem. Index by user_id to fetch a single user's actions, and keep events sorted by timestamp for binary range search. getUserActions binary-searches that user's sorted list; countUniqueUsers scans the global sorted events and deduplicates with a set.
import bisect
from collections import defaultdict
class LogStore:
def __init__(self):
self.by_user = defaultdict(list) # user_id -> sorted [(ts, action)]
self.events = [] # global sorted [(ts, user_id)]
def record(self, user_id, action_type, ts):
# assume near-sorted arrival; insert to keep order if needed
self.by_user[user_id].append((ts, action_type))
bisect.insort(self.events, (ts, user_id))
def getUserActions(self, user_id, start, end):
arr = self.by_user.get(user_id, [])
lo = bisect.bisect_left(arr, (start,))
hi = bisect.bisect_right(arr, (end, chr(0x10FFFF)))
return [a for _, a in arr[lo:hi]]
def countUniqueUsers(self, start, end):
lo = bisect.bisect_left(self.events, (start, 0))
hi = bisect.bisect_right(self.events, (end, float("inf")))
return len({uid for _, uid in self.events[lo:hi]})
The interviewer cared a lot about performance at scale and asked whether a single index structure could serve both methods—a deep discussion that boils down to trading space for time. Complexity: getUserActions O(log n + k); countUniqueUsers O(log n + m).
Round 4: Hiring Manager Competency
The final round skips algorithms and focuses on experience and collaboration. The HM introduced the team's infra work, then asked:
- Have you designed a system from scratch?
- Have you mentored newer engineers?
- Have you refactored legacy code and driven the team to adopt new tooling?
I centered on an async messaging system from design through rollout, and how I drove the whole team to migrate. The conversation was relaxed, but the HM was evaluating your communication style and influence.
What to Prioritize
| Skill | How to practice |
|---|---|
| State modeling | Expand "node" into "node + extra state"; drill BFS/Dijkstra variants |
| Interface design | Practice data-access API design; think through the index structure |
| Trade-off framing | For each approach, name 2 alternatives and the reason you chose one |
| HM stories | Prepare design-to-rollout, mentoring, and driving-change narratives |
FAQ
How many rounds is the Pinterest SDE VO?
Three coding rounds plus one Hiring Manager conversation. The coding rounds emphasize code quality and boundary handling; the HM round covers collaboration and influence, evaluating culture fit and ownership rather than algorithms.
Are Pinterest problems really that hard?
They have a hard reputation but land around medium. Problems aren't obscure and don't chase tricks, but follow-ups run deep and coding rounds often embed system design. Naming, boundaries, and extensibility matter more than clever tricks.
Do algorithm rounds ask about thread safety?
Yes, often unexpectedly. The LRU problem drew questions on whether you need a lock and whether a slow callback blocks the main flow. Prepping answers on async handling, lock granularity, and concurrent access earns points.
What's the highest-leverage way to prep the Pinterest VO?
Drill problems close to real business logic, especially design problems with state management or data-access interfaces. If you want timed mocks of these three problems, variant extensions, or live VO support / VO proxy pairing, share the job description so we can predict the problem set and plan practice.
Preparing for the Pinterest SDE VO?
Pinterest tests engineering-grade code quality and systems thinking, not rote grinding. oavoservice offers full VO coaching for Pinterest and top internet companies: timed three-round coding mocks, HM competency story polishing, and design-problem trade-off breakdowns, plus live VO support / VO proxy pairing. Coaches include former big-tech senior engineers familiar with Pinterest's "coding-with-embedded-design" scoring style.
Add WeChat Coding0201 to book Pinterest VO coaching.
Contact
- WeChat: Coding0201
- Email: [email protected]
- Telegram: @OAVOProxy