2254. Design Video Sharing Platform
On LeetCode ->Problem¶
Build a video platform that assigns each upload the smallest available nonnegative ID. Support deletion, inclusive-range watching, and per-video view, like, and dislike counts. Missing IDs return the specified sentinel values.
class VideoSharingPlatform:
def __init__(self):
pass
def upload(self, video: str) -> int:
pass
def remove(self, videoId: int) -> None:
pass
def watch(self, videoId: int, startMinute: int, endMinute: int) -> str:
pass
def like(self, videoId: int) -> None:
pass
def dislike(self, videoId: int) -> None:
pass
def getLikesAndDislikes(self, videoId: int) -> list[int]:
pass
def getViews(self, videoId: int) -> int:
pass
Key trick¶
Keep deleted IDs in a min-heap. If the heap is empty, assign the next unused ID.
Trap¶
Python slices exclude the end index: an inclusive endMinute requires endMinute + 1. Reusing an ID must also reset all its counts.
Why is it interesting?¶
It combines ID allocation, object state, and an easy-to-miss difference between inclusive problem boundaries and exclusive Python slices.
Python solution¶
import heapq
class VideoSharingPlatform:
def __init__(self):
self.videos = {}
self.available_ids = []
self.next_id = 0
def upload(self, video: str) -> int:
if self.available_ids:
videoId = heapq.heappop(self.available_ids)
else:
videoId = self.next_id
self.next_id += 1
# Store content, views, likes, and dislikes for this upload.
self.videos[videoId] = [video, 0, 0, 0]
return videoId
def remove(self, videoId: int) -> None:
if videoId in self.videos:
del self.videos[videoId]
heapq.heappush(self.available_ids, videoId)
def watch(self, videoId: int, startMinute: int, endMinute: int) -> str:
if videoId not in self.videos:
return "-1"
video = self.videos[videoId]
video[1] += 1
# Slicing caps the end at the video length automatically.
return video[0][startMinute:endMinute + 1]
def like(self, videoId: int) -> None:
if videoId in self.videos:
self.videos[videoId][2] += 1
def dislike(self, videoId: int) -> None:
if videoId in self.videos:
self.videos[videoId][3] += 1
def getLikesAndDislikes(self, videoId: int) -> list[int]:
if videoId not in self.videos:
return [-1]
return self.videos[videoId][2:4]
def getViews(self, videoId: int) -> int:
if videoId not in self.videos:
return -1
return self.videos[videoId][1]
Complexity: Upload and removal take \(O(\log d)\) with \(d\) deleted IDs; other operations take \(O(1)\), except watching, which takes \(O(k)\) for the returned substring. Space is \(O(L+d)\) for stored video content of total length \(L\) and deleted IDs.
Comment on my solution¶
Your ID reuse and counter handling are correct. The watch slice drops the final requested digit because its end is exclusive; replace the slice with video["content"][startMinute:endMinute + 1]. Python already caps a slice at the string’s length.
import heapq
# WRONG
class VideoSharingPlatform:
def __init__(self):
self.videos = {} # video_id -> {content -> "...", likes: 0, dislikes: 0, views: 0}
self.next_id = 0
self.available_ids = [] # min heap of the video ids of removed videos
def upload(self, video: str):
if self.available_ids:
video_id = heapq.heappop(self.available_ids)
else:
video_id = self.next_id
self.next_id += 1
self.videos[video_id] = {"content": video,
"views": 0,
"likes": 0,
"dislikes": 0}
return video_id
def remove(self, videoId: int):
if videoId in self.videos:
del self.videos[videoId]
heapq.heappush(self.available_ids, videoId)
def watch(self, videoId: int, startMinute: int, endMinute: int):
video = self.videos.get(videoId)
if video:
video["views"] += 1
video_length = len(video["content"])
return video["content"][startMinute:min(endMinute, video_length - 1)]
return "-1"
def like(self, videoId: int):
video = self.videos.get(videoId)
if video:
video["likes"] += 1
def dislike(self, videoId: int):
video = self.videos.get(videoId)
if video:
video["dislikes"] += 1
def getLikesAndDislikes(self, videoId: int):
video = self.videos.get(videoId)
if video:
return [video["likes"], video["dislikes"]]
return [-1]
def getViews(self, videoId: int):
video = self.videos.get(videoId)
if video:
return video["views"]
return -1
Extra¶
Problem description¶
You have a video sharing platform where users can upload and delete
videos. Each video is a string of digits, where the ith digit of
the string represents the content of the video at minute i. For
example, the first digit represents the content at minute 0 in the
video, the second digit represents the content at minute 1 in the
video, and so on. Viewers of videos can also like and dislike videos.
Internally, the platform keeps track of the number of views, likes,
and dislikes on each video.
When a video is uploaded, it is associated with the smallest available
integer videoId starting from 0. Once a video is deleted, the
videoId associated with that video can be reused for another video.
Implement the VideoSharingPlatform class:
VideoSharingPlatform()Initializes the object.int upload(String video)The user uploads avideo. Return thevideoIdassociated with the video.void remove(int videoId)If there is a video associated withvideoId, remove the video.String watch(int videoId, int startMinute, int endMinute)If there is a video associated withvideoId, increase the number of views on the video by1and return the substring of the video string starting atstartMinuteand ending atmin(endMinute, video.length - 1``)(inclusive). Otherwise, return"-1".void like(int videoId)Increases the number of likes on the video associated withvideoIdby1if there is a video associated withvideoId.void dislike(int videoId)Increases the number of dislikes on the video associated withvideoIdby1if there is a video associated withvideoId.int[] getLikesAndDislikes(int videoId)Return a 0-indexed integer arrayvaluesof length2wherevalues[0]is the number of likes andvalues[1]is the number of dislikes on the video associated withvideoId. If there is no video associated withvideoId, return[-1].int getViews(int videoId)Return the number of views on the video associated withvideoId, if there is no video associated withvideoId, return-1.
Example 1:
Input
["VideoSharingPlatform", "upload", "upload", "remove", "remove", "upload", "watch", "watch", "like", "dislike", "dislike", "getLikesAndDislikes", "getViews"]
[[], ["123"], ["456"], [4], [0], ["789"], [1, 0, 5], [1, 0, 1], [1], [1], [1], [1], [1]]
Output
[null, 0, 1, null, null, 0, "456", "45", null, null, null, [1, 2], 2]
Explanation
VideoSharingPlatform videoSharingPlatform = new VideoSharingPlatform();
videoSharingPlatform.upload("123"); // The smallest available videoId is 0, so return 0.
videoSharingPlatform.upload("456"); // The smallest available videoId is 1, so return 1.
videoSharingPlatform.remove(4); // There is no video associated with videoId 4, so do nothing.
videoSharingPlatform.remove(0); // Remove the video associated with videoId 0.
videoSharingPlatform.upload("789"); // Since the video associated with videoId 0 was deleted,
// 0 is the smallest available videoId, so return 0.
videoSharingPlatform.watch(1, 0, 5); // The video associated with videoId 1 is "456".
// The video from minute 0 to min(5, 3 - 1) = 2 is "456", so return "456".
videoSharingPlatform.watch(1, 0, 1); // The video associated with videoId 1 is "456".
// The video from minute 0 to min(1, 3 - 1) = 1 is "45", so return "45".
videoSharingPlatform.like(1); // Increase the number of likes on the video associated with videoId 1.
videoSharingPlatform.dislike(1); // Increase the number of dislikes on the video associated with videoId 1.
videoSharingPlatform.dislike(1); // Increase the number of dislikes on the video associated with videoId 1.
videoSharingPlatform.getLikesAndDislikes(1); // There is 1 like and 2 dislikes on the video associated with videoId 1, so return [1, 2].
videoSharingPlatform.getViews(1); // The video associated with videoId 1 has 2 views, so return 2.
Example 2:
Input
["VideoSharingPlatform", "remove", "watch", "like", "dislike", "getLikesAndDislikes", "getViews"]
[[], [0], [0, 0, 1], [0], [0], [0], [0]]
Output
[null, null, "-1", null, null, [-1], -1]
Explanation
VideoSharingPlatform videoSharingPlatform = new VideoSharingPlatform();
videoSharingPlatform.remove(0); // There is no video associated with videoId 0, so do nothing.
videoSharingPlatform.watch(0, 0, 1); // There is no video associated with videoId 0, so return "-1".
videoSharingPlatform.like(0); // There is no video associated with videoId 0, so do nothing.
videoSharingPlatform.dislike(0); // There is no video associated with videoId 0, so do nothing.
videoSharingPlatform.getLikesAndDislikes(0); // There is no video associated with videoId 0, so return [-1].
videoSharingPlatform.getViews(0); // There is no video associated with videoId 0, so return -1.
Constraints:
1 <= video.length <= 10^5- The sum of
video.lengthover all calls touploaddoes not exceed10^5 videoconsists of digits.0 <= videoId <= 10^50 <= startMinute < endMinute < 10^5startMinute < video.length- The sum of
endMinute - startMinuteover all calls towatchdoes not exceed10^5. - At most
10^5calls in total will be made to all functions.