Design a class MusicPlayer that supports the following operations:
play(songId: int): Play a song. If the song is already in the playlist, move it to the end (most recently played).
getRecentlyPlayed(n: int): Return the n most recently played unique songs. If there are fewer than n songs in the playlist, return all of them.
getTopSongs(n: int): Return the n most played songs, sorted by play count (descending). If multiple songs have the same play count, sort them by most recently played.
This problem would test your ability to design a system that efficiently manages a playlist, keeps track of play counts, and retrieves recently played and top songs.
Okay let’s see:
I actually right that code right here in Obsidian. Then I brought it into VScode and cleaned it up to be, eventually, this:
But I think I spent two hours on this. I know. It was rough. I was very close, but I got super stuck. I believe that my playSong method was messed up and not adding things correctly.
So algorithmically, things were good almost from the beginning. A couple things to tighten up, but otherwise great.
Codewise, writing everything in one without verifying that the first functions worked was a huge no-no and made it very hard to debug things.
Return #1
I struggled with this one, specifically using data structures in the optimal way. So I looked around to find alternatives. I found this and learned some cool things from it:
Key Takeaways
maintaining multiple data structures for different use cases isn’t ideal. It just requires keeping track of writes and updates. In this case, the writes and updates are all in one method, so it’s not bad.
Sets, in addition to Maps, also keep track of order of insertion
Unlike array access, the .slice() method allows for negative indexes! Since the second argument of slice is the end of the slice, exclusive, -1 returns one less at the end of the selection that passing arr.length