PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep

Quick Overview

This question evaluates data structures, state-management, and algorithmic skills for tracking per-user votes, detecting vote flips, maintaining a most-recent unique flip history per user, and computing dynamic top-k article rankings.

  • medium
  • Rippling
  • Coding & Algorithms
  • Software Engineer

Implement Article Vote Tracking

Company: Rippling

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Technical Screen

We are building an in-memory vote management service for an online news platform. Users can upvote or downvote published articles, and we want to track cases where users change their minds. Implement a `VoteService` with the following APIs: ```python add_article(article_name: str) -> int ``` Adds a new article and returns its integer article ID. Article IDs are assigned incrementally starting from `1`. ```python upvote_article(article_id: int, user_id: int) -> None ``` Records an upvote from the given user for the given article. ```python downvote_article(article_id: int, user_id: int) -> None ``` Records a downvote from the given user for the given article. Assumptions: - Every `user_id` is valid. - Every `article_id` passed to a vote method has already been added. - Store all data in memory. - Do not worry about thread safety or persistence. - The system should be designed with future scale in mind: millions of users and articles. A user is considered to have "flipped" on an article when their vote changes from upvote to downvote or from downvote to upvote. A user's first vote on an article is not a flip. Implement: ```python print_last_three_flips(user_id: int) -> None ``` This should print the article names for the last three unique articles on which the given user flipped their vote, ordered from most recent to least recent. If the same article is flipped multiple times, it should appear only once in this list, at its most recent position. Then extend the service with: ```python get_top_k(k: int) -> list[str] ``` Return the names of the top `k` articles by current score. Each user's latest upvote contributes `+1`; each user's latest downvote contributes `-1`. Repeating the same vote should not change the score, while flipping from upvote to downvote or downvote to upvote should update the score accordingly.

Quick Answer: This question evaluates data structures, state-management, and algorithmic skills for tracking per-user votes, detecting vote flips, maintaining a most-recent unique flip history per user, and computing dynamic top-k article rankings.

Part 1: Track the Last Three Flipped Articles per User

You are given a chronological list of operations for an in-memory article vote service. When an article is added, it receives the next integer ID starting from 1. Users can upvote or downvote articles. A user's first vote on an article is not a flip. A flip happens only when the user's new vote on the same article changes from upvote to downvote or from downvote to upvote. Repeating the same vote does nothing. For every query operation `('last_three_flips', user_id)`, return the names of the last three unique articles on which that user flipped, ordered from most recent to least recent. If the same article is flipped multiple times, it should appear only once, at its most recent position. Implement a function that processes all operations and returns the answers for all `last_three_flips` queries in order.

Constraints

  • 1 <= len(operations) <= 200000
  • Article IDs are assigned incrementally starting from 1 in the order of `add` operations
  • Every `article_id` in a vote operation is valid
  • 0 <= user_id <= 10^9
  • Article names are non-empty strings
  • If a user has fewer than 3 flipped articles, return all of them
  • If a user has never flipped on any article, return an empty list for that query

Examples

Input: ([('add_article', 'Alpha'), ('add_article', 'Beta'), ('upvote', 'u1', 1), ('downvote', 'u1', 1), ('upvote', 'u1', 2), ('downvote', 'u1', 2), ('last_three_flips', 'u1')],)

Expected Output: [['Beta', 'Alpha']]

Explanation: Alpha is flipped first, then Beta is flipped later, so Beta is returned before Alpha.

Input: ([('add_article', 'Alpha'), ('add_article', 'Beta'), ('upvote', 'u1', 1), ('downvote', 'u1', 1), ('upvote', 'u1', 2), ('downvote', 'u1', 2), ('upvote', 'u1', 1), ('last_three_flips', 'u1')],)

Expected Output: [['Alpha', 'Beta']]

Explanation: Alpha flips, then Beta flips, then Alpha flips again. Alpha should move to the front and appear only once.

Input: ([('add_article', 'Alpha'), ('upvote', 'u1', 1), ('upvote', 'u1', 1), ('last_three_flips', 'u1'), ('last_three_flips', 'u2')],)

Expected Output: [[], []]

Explanation: The second upvote repeats the same vote, so no flip is recorded. A user with no flips returns an empty list.

Input: ([('add_article', 'A'), ('add_article', 'B'), ('add_article', 'C'), ('add_article', 'D'), ('upvote', 'u1', 1), ('downvote', 'u1', 1), ('upvote', 'u1', 2), ('downvote', 'u1', 2), ('upvote', 'u1', 3), ('downvote', 'u1', 3), ('upvote', 'u1', 4), ('downvote', 'u1', 4), ('last_three_flips', 'u1')],)

Expected Output: [['D', 'C', 'B']]

Explanation: Four different articles are flipped, but only the three most recent unique flipped articles are returned.

Input: ([('add_article', 'Alpha'), ('add_article', 'Beta'), ('add_article', 'Gamma'), ('upvote', 'u1', 1), ('downvote', 'u1', 1), ('downvote', 'u2', 2), ('upvote', 'u2', 2), ('upvote', 'u1', 3), ('downvote', 'u1', 3), ('last_three_flips', 'u2'), ('last_three_flips', 'u1')],)

Expected Output: [['Beta'], ['Gamma', 'Alpha']]

Explanation: Each user has an independent vote history and flip order.

Input: ([],)

Expected Output: []

Explanation: With no operations, there are no query answers to return.

Hints

  1. Track the latest vote for each `(article_id, user_id)` pair so you can detect whether a new vote is a real flip.
  2. For each user, maintain an ordered set/map of flipped article IDs. On a new flip, move that article to the most recent position instead of storing duplicates.

Part 2: Return the Top K Articles by Current Score

You are given a chronological list of operations for an in-memory article vote service. When an article is added, it receives the next integer ID starting from 1. Users can upvote or downvote articles. Each user's latest vote on an article determines that user's contribution to the article's score: - latest upvote contributes `+1` - latest downvote contributes `-1` - the first vote sets the contribution - repeating the same vote changes nothing - flipping from upvote to downvote or downvote to upvote updates the score accordingly For every query operation `('top_k', k)`, return the names of the top `k` articles by current score. If two articles have the same score, return the one with the smaller article ID first (the one added earlier). If fewer than `k` articles exist, return all of them. Implement a function that processes all operations and returns the answers for all `top_k` queries in order.

Constraints

  • 1 <= len(operations) <= 200000
  • 0 <= sum of all k values across `top_k` queries <= 200000
  • Article IDs are assigned incrementally starting from 1 in the order of `add` operations
  • Every `article_id` in a vote operation is valid
  • 0 <= user_id <= 10^9
  • 0 <= k <= number of added articles is allowed, but if k is larger, return all available articles
  • Tie-break equal scores by smaller article ID first

Examples

Input: [('add', 'Alpha'), ('add', 'Beta'), ('upvote', 'alice', 1), ('top_k', 2)]

Expected Output: [['Alpha', 'Beta']]

Explanation: Alpha has score 1 and Beta has score 0, so Alpha comes first.

Input: [('add', 'Alpha'), ('add', 'Beta'), ('upvote', 'alice', 2), ('upvote', 'bob', 2), ('upvote', 'cara', 1), ('top_k', 2)]

Expected Output: [['Beta', 'Alpha']]

Explanation: Beta has score 2 and Alpha has score 1, so Beta ranks higher.

Input: [('add', 'Gamma'), ('add', 'Delta'), ('upvote', 'u1', 1), ('upvote', 'u1', 1), ('downvote', 'u1', 1), ('upvote', 'u2', 2), ('top_k', 2)]

Expected Output: [['Delta', 'Gamma']]

Explanation: Gamma goes from 0 to 1, repeated upvote changes nothing, then flips to -1. Delta gets +1, so Delta ranks above Gamma.

Input: [('add', 'First'), ('add', 'Second'), ('upvote', 'u1', 2), ('upvote', 'u2', 1), ('top_k', 2)]

Expected Output: [['First', 'Second']]

Explanation: Both articles have score 1, so the smaller article ID wins the tie. First was added earlier.

Input: [('top_k', 3), ('add', 'Solo'), ('top_k', 5)]

Expected Output: [[], ['Solo']]

Explanation: Before any article exists, the answer is an empty list. Later, only Solo exists, so it is returned even though k is 5.

Input: [('add', 'Alpha'), ('add', 'Beta'), ('upvote', 'alice', 1), ('top_k', 2), ('upvote', 'bob', 2), ('upvote', 'cara', 2), ('top_k', 2)]

Expected Output: [['Alpha', 'Beta'], ['Beta', 'Alpha']]

Explanation: The function must return answers for all top_k queries in order. After the later votes, Beta overtakes Alpha.

Hints

  1. Store the latest vote for each `(article_id, user_id)` pair and update the article score by `new_vote - old_vote` whenever the vote changes.
  2. To answer many `top_k` queries efficiently, maintain a heap of candidate scores and use lazy deletion (for example, with version numbers) to ignore stale entries.
Last updated: Jun 12, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,500+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Compare Complete and Partial Poker Hands - Rippling (medium)
  • Implement Courier Delivery Cost Tracking - Rippling (medium)
  • Implement logger and card ranking - Rippling (medium)
  • Design a Driver Payroll System - Rippling (medium)
  • Compare Complete or Partial Hands - Rippling (medium)