Level: Unknown Level
Round: Full Journey · Type: Coding · Difficulty: 7/10 · Duration: 180 min · Interviewer: Neutral
Topics: Object-Oriented Programming, Data Structures, Hashmaps, Lists, Heaps, Time Complexity, Space Complexity, Concurrency, LRU Cache
Location: San Francisco Bay Area
Interview date: 2025-12-28
Question: Implement a MusicPlayer class with add_song, play_song, and print_analytics_summary methods. I needed to handle song additions, track plays, and output analytics.
Question: Add a method to get the last 3 unique songs played by a user, considering replay updates and memory limits. The history should update when a song is replayed.
Question: Implement a method to print the top K songs based on unique listeners, optimized for performance using a min-heap. The goal was to achieve better than O(N log N) time complexity.
The interview involved building a music player system in three parts, similar to Spotify, focusing on efficiency and data structures.
Part 1: Basic Setup
I had to create a MusicPlayer class with methods to add songs, record song plays, and print an analytics summary. I used HashMaps and Lists for efficient lookups and handled edge cases like duplicate song plays. For example, Alice playing 'Bohemian Rhapsody' twice should only count as one unique listener.
The required methods were:
` class MusicPlayer: def add_song(self, song_title: str) -> int: """ Add a song to the library.
Args:
song_title: Name of the song
Returns:
A unique song_id (integer) for this song
"""
pass
def play_song(self, song_id: int, user_id: str) -> None:
"""
Record that a user played a song.
Args:
song_id: The ID of the song
user_id: The ID of the user
"""
pass
def print_analytics_summary(self) -> None:
"""
Print a list of songs and how many unique people listened to them.
Format: "song_title: N unique listeners"
Order: Print in the order the songs were added.
"""
pass
For example:
player = MusicPlayer()
song1 = player.add_song("Bohemian Rhapsody") # Returns 1 song2 = player.add_song("Stairway to Heaven") # Returns 2 song3 = player.add_song("Hotel California") # Returns 3
player.play_song(1, "alice") player.play_song(1, "bob") player.play_song(1, "alice") # Alice plays it again (duplicate) player.play_song(2, "alice") player.play_song(2, "charlie") player.play_song(3, "alice")
player.print_analytics_summary()
Should output:
Bohemian Rhapsody: 2 unique listeners
Stairway to Heaven: 2 unique listeners
Hotel California: 1 unique listener
`
Part 2: User History
I needed to add a method to track the last 3 unique songs a user played, ensuring the list was in the correct order and respecting memory limits. Replaying a song should move it to the front of the history. The interviewer emphasized only storing 3 songs per user and updating the history correctly on replays.
The method signature was:
` def last_three_played_song_titles(self, user_id: str) -> list[str]: """ Get the last 3 unique songs played by a user.
Args:
user_id: The ID of the user
Returns:
List of song titles (newest first).
If less than 3, return all of them.
If no history, return empty list.
"""
pass
For example:
player = MusicPlayer()
song1 = player.add_song("Song A") # ID: 1 song2 = player.add_song("Song B") # ID: 2 song3 = player.add_song("Song C") # ID: 3 song4 = player.add_song("Song D") # ID: 4
player.play_song(1, "alice") # History: [A] player.play_song(2, "alice") # History: [B, A] player.play_song(3, "alice") # History: [C, B, A] player.play_song(4, "alice") # History: [D, C, B] - A is removed
print(player.last_three_played_song_titles("alice")) # ["Song D", "Song C", "Song B"]
player.play_song(2, "alice") # History: [B, D, C] - B moves to front
print(player.last_three_played_song_titles("alice")) # ["Song B", "Song D", "Song C"] `
Part 3: Top Songs Analysis
I was asked to implement a method to print the top K songs based on unique listeners, with the requirement of being faster than O(N log N). A min-heap of size K was suggested as the optimal solution. The interviewer wanted to see how I could optimize for performance.
The method signature was:
` def print_top_k_analytics_summary(self, k: int) -> None: """ Print the top K songs by unique listener count.
Args:
k: Number of songs to show
Order: By listener count (high to low). If there is a tie, use song_id.
Requirement: Faster than O(N log N).
"""
pass
For example:
player = MusicPlayer()
titles = ["Shape of You", "Blinding Lights", "Dance Monkey", "Someone Like You", "Bad Guy"] for t in titles: player.add_song(t)
player.print_top_k_analytics_summary(3)
Should output:
Someone Like You: 4 unique listeners
Shape of You: 3 unique listeners
Dance Monkey: 2 unique listeners
`
I was also asked about time complexity for each function and how to handle concurrency (using locks or thread-safe data structures) and extensions like time-based analytics (storing timestamps) and leaderboards (using a balanced tree or skip list).