Design Video Sharing Platform
Problem
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.
Examples
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 exceed105 videoconsists of digits.0 <= videoId <= 10^50 <= startMinute < endMinute < 10^5startMinute < video.length- The sum of
endMinute - startMinuteover all calls towatchdoes not exceed105. - At most
105calls in total will be made to all functions.
Solution
Method 1 – Hash Maps, Min Heap, and Struct for Video Info
Intuition
We need to efficiently manage video uploads, removals, and queries for views, likes, and dislikes, while reusing the smallest available videoId. A min heap can track available ids, and a hash map can store video info.
Approach
- Use a min heap to track available videoIds. If empty, use the next sequential id.
- Use a hash map to store video info: content, views, likes, dislikes for each videoId.
- For
upload, assign the smallest available id, store the video, and return the id. - For
remove, delete the video and add its id to the heap. - For
watch, if the video exists, increment views and return the substring; else return "-1". - For
like/dislike, increment the respective counter if the video exists. - For
getLikesAndDislikes, return [likes, dislikes] or [-1] if not found. - For
getViews, return views or -1 if not found.
Code
C++
class VideoSharingPlatform {
struct Info {
string content;
int views = 0, likes = 0, dislikes = 0;
};
unordered_map<int, Info> vids;
priority_queue<int, vector<int>, greater<int>> freeIds;
int nextId = 0;
public:
VideoSharingPlatform() {}
int upload(string video) {
int id = freeIds.empty() ? nextId++ : freeIds.top();
if (!freeIds.empty()) freeIds.pop();
vids[id] = {video, 0, 0, 0};
return id;
}
void remove(int videoId) {
if (vids.count(videoId)) {
vids.erase(videoId);
freeIds.push(videoId);
}
}
string watch(int videoId, int start, int end) {
if (!vids.count(videoId)) return "-1";
auto& v = vids[videoId];
v.views++;
int l = v.content.size();
int e = min(end, l-1);
return v.content.substr(start, e-start+1);
}
void like(int videoId) { if (vids.count(videoId)) vids[videoId].likes++; }
void dislike(int videoId) { if (vids.count(videoId)) vids[videoId].dislikes++; }
vector<int> getLikesAndDislikes(int videoId) {
if (!vids.count(videoId)) return {-1};
return {vids[videoId].likes, vids[videoId].dislikes};
}
int getViews(int videoId) {
if (!vids.count(videoId)) return -1;
return vids[videoId].views;
}
};
Go
type Info struct {
content string
views int
likes int
dislikes int
}
type VideoSharingPlatform struct {
vids map[int]*Info
freeIds []int
nextId int
}
func Constructor() VideoSharingPlatform {
return VideoSharingPlatform{vids: map[int]*Info{}}
}
func (v *VideoSharingPlatform) Upload(video string) int {
id := v.nextId
if len(v.freeIds) > 0 {
id = v.freeIds[0]
v.freeIds = v.freeIds[1:]
} else {
v.nextId++
}
v.vids[id] = &Info{content: video}
return id
}
func (v *VideoSharingPlatform) Remove(videoId int) {
if _, ok := v.vids[videoId]; ok {
delete(v.vids, videoId)
v.freeIds = append(v.freeIds, videoId)
sort.Ints(v.freeIds)
}
}
func (v *VideoSharingPlatform) Watch(videoId, start, end int) string {
info, ok := v.vids[videoId]
if !ok {
return "-1"
}
info.views++
l := len(info.content)
e := end
if e >= l {
e = l - 1
}
return info.content[start : e+1]
}
func (v *VideoSharingPlatform) Like(videoId int) {
if info, ok := v.vids[videoId]; ok {
info.likes++
}
}
func (v *VideoSharingPlatform) Dislike(videoId int) {
if info, ok := v.vids[videoId]; ok {
info.dislikes++
}
}
func (v *VideoSharingPlatform) GetLikesAndDislikes(videoId int) []int {
if info, ok := v.vids[videoId]; ok {
return []int{info.likes, info.dislikes}
}
return []int{-1}
}
func (v *VideoSharingPlatform) GetViews(videoId int) int {
if info, ok := v.vids[videoId]; ok {
return info.views
}
return -1
}
Java
public class VideoSharingPlatform {
static class Info {
String content;
int views, likes, dislikes;
Info(String c) { content = c; }
}
Map<Integer, Info> vids = new HashMap<>();
PriorityQueue<Integer> freeIds = new PriorityQueue<>();
int nextId = 0;
public VideoSharingPlatform() {}
public int upload(String video) {
int id = freeIds.isEmpty() ? nextId++ : freeIds.poll();
vids.put(id, new Info(video));
return id;
}
public void remove(int videoId) {
if (vids.containsKey(videoId)) {
vids.remove(videoId);
freeIds.offer(videoId);
}
}
public String watch(int videoId, int start, int end) {
if (!vids.containsKey(videoId)) return "-1";
Info v = vids.get(videoId);
v.views++;
int l = v.content.length();
int e = Math.min(end, l-1);
return v.content.substring(start, e+1);
}
public void like(int videoId) { if (vids.containsKey(videoId)) vids.get(videoId).likes++; }
public void dislike(int videoId) { if (vids.containsKey(videoId)) vids.get(videoId).dislikes++; }
public int[] getLikesAndDislikes(int videoId) {
if (!vids.containsKey(videoId)) return new int[]{-1};
Info v = vids.get(videoId);
return new int[]{v.likes, v.dislikes};
}
public int getViews(int videoId) {
if (!vids.containsKey(videoId)) return -1;
return vids.get(videoId).views;
}
}
Kotlin
class VideoSharingPlatform {
data class Info(var content: String, var views: Int = 0, var likes: Int = 0, var dislikes: Int = 0)
private val vids = mutableMapOf<Int, Info>()
private val freeIds = java.util.PriorityQueue<Int>()
private var nextId = 0
fun upload(video: String): Int {
val id = if (freeIds.isEmpty()) nextId++ else freeIds.poll()
vids[id] = Info(video)
return id
}
fun remove(videoId: Int) {
if (vids.remove(videoId) != null) freeIds.add(videoId)
}
fun watch(videoId: Int, start: Int, end: Int): String {
val v = vids[videoId] ?: return "-1"
v.views++
val e = minOf(end, v.content.length-1)
return v.content.substring(start, e+1)
}
fun like(videoId: Int) { vids[videoId]?.let { it.likes++ } }
fun dislike(videoId: Int) { vids[videoId]?.let { it.dislikes++ } }
fun getLikesAndDislikes(videoId: Int): IntArray = vids[videoId]?.let { intArrayOf(it.likes, it.dislikes) } ?: intArrayOf(-1)
fun getViews(videoId: Int): Int = vids[videoId]?.views ?: -1
}
Python
import heapq
class VideoSharingPlatform:
def __init__(self):
self.vids = {}
self.free = []
self.next_id = 0
def upload(self, video: str) -> int:
if self.free:
vid = heapq.heappop(self.free)
else:
vid = self.next_id
self.next_id += 1
self.vids[vid] = {'content': video, 'views': 0, 'likes': 0, 'dislikes': 0}
return vid
def remove(self, videoId: int) -> None:
if videoId in self.vids:
del self.vids[videoId]
heapq.heappush(self.free, videoId)
def watch(self, videoId: int, start: int, end: int) -> str:
if videoId not in self.vids:
return "-1"
v = self.vids[videoId]
v['views'] += 1
e = min(end, len(v['content'])-1)
return v['content'][start:e+1]
def like(self, videoId: int) -> None:
if videoId in self.vids:
self.vids[videoId]['likes'] += 1
def dislike(self, videoId: int) -> None:
if videoId in self.vids:
self.vids[videoId]['dislikes'] += 1
def getLikesAndDislikes(self, videoId: int) -> list[int]:
if videoId not in self.vids:
return [-1]
v = self.vids[videoId]
return [v['likes'], v['dislikes']]
def getViews(self, videoId: int) -> int:
if videoId not in self.vids:
return -1
return self.vids[videoId]['views']
Complexity
- ⏰ Time complexity:
O(log n)for upload/remove (heap),O(1)for other operations. - 🧺 Space complexity:
O(n), wherenis the number of videos stored.