2254. Design Video Sharing Platform


Problem Description

You are required to design and implement a simple video sharing platform. The platform allows users to perform the following actions:

  1. Upload videos: Each video is represented as 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. When a video is uploaded, it is assigned the smallest available integer videoId starting from 0.
  2. Delete videos: Users can delete videos by specifying the videoId. Once a video is deleted, the videoId associated with that video can be reused for another video.
  3. Watch videos: Viewers can watch a part of the video by specifying the videoId, startMinute, and endMinute. The platform should return the content of the video for the specified duration.
  4. Like and dislike videos: Viewers can like and dislike videos by specifying the videoId. The platform should keep track of the number of likes and dislikes for each video.
  5. Get statistics: The platform should be able to provide the number of views, likes, and dislikes for a given video by its videoId.

Example

  1. Upload a video: Let's assume a user uploads a video with content "12345". The platform assigns videoId 0 to this video.

  2. View a video: A viewer watches the video with videoId 0 from minute 1 to minute 3. The platform should return the content "234".

  3. Like and dislike: The viewer likes the video with videoId 0. Now the video has 1 like. Another viewer dislikes the video. Now it has 1 dislike.

  4. Get statistics: The platform should return the statistics for the video with videoId 0 => views: 1, likes: 1, dislikes: 1.

  5. Delete a video: A user deletes the video with videoId 0.

  6. Upload another video: A user uploads a new video with content "678910". Since 0 was freed up after deleting the previous video, the platform assigns videoId 0 to this new video.

Approach

We can use the following data structures for this problem:

  1. A priority queue usedIds to keep track of the available (deleted) videoIds in increasing order.
  2. An integer currVideoId initialized as 0 to keep track of the new videoId to be assigned for the next upload.
  3. A set of maps videoIdToVideo, videoIdToViews, videoIdToLikes, and videoIdToDislikes to store the video content, views, likes, and dislikes for each video by its videoId.

The main idea is to use these data structures to efficiently perform the required actions like upload, delete, watch, like, dislike, and get statistics.

Algorithm

  1. For video upload, first check if the usedIds priority queue is empty. If empty, assign the current currVideoId to the video and increment it by 1. If not empty, get the minimum videoId from the priority queue, remove it, and assign to the video. In both cases, add the video content to the videoIdToVideo map.

  2. For video delete, first check if the video with the given videoId exists in the videoIdToVideo map. If yes, add the videoId to the usedIds priority queue and remove the videoId from all the maps.

  3. For watching a video, first check if the video with the given videoId exists in the videoIdToVideo map. If yes, increment the views count in the videoIdToViewsmap, and return the video content for the specified duration. If not, return "-1".

  4. For liking and disliking a video, first check if the video with the given videoId exists in the videoIdToVideo map. If yes, increment the likes or dislikes count in the respective maps.

  5. For getting statistics, first check if the video with the given videoId exists in the videoIdToVideo map. If yes, return the views, likes, and dislikes from the respective maps. If not, return -1.

Solution

1
2python
3from queue import PriorityQueue
4from collections import defaultdict
5
6class VideoSharingPlatform:
7
8    def __init__(self):
9        self.currVideoId = 0
10        self.usedIds = PriorityQueue()
11        self.videoIdToVideo = {}
12        self.videoIdToViews = defaultdict(int)
13        self.videoIdToLikes = defaultdict(int)
14        self.videoIdToDislikes = defaultdict(int)
15
16    def getVideoId(self):
17        if self.usedIds.empty():
18            videoId = self.currVideoId
19            self.currVideoId += 1
20        else:
21            videoId = self.usedIds.get()
22        return videoId
23
24    def upload(self, video: str) -> int:
25        videoId = self.getVideoId()
26        self.videoIdToVideo[videoId] = video
27        return videoId
28
29    def remove(self, videoId: int) -> None:
30        if videoId in self.videoIdToVideo:
31            self.usedIds.put(videoId)
32            del self.videoIdToVideo[videoId]
33            del self.videoIdToViews[videoId]
34            del self.videoIdToLikes[videoId]
35            del self.videoIdToDislikes[videoId]
36
37    def watch(self, videoId: int, startMinute: int, endMinute: int) -> str:
38        if videoId not in self.videoIdToVideo:
39            return "-1"
40        self.videoIdToViews[videoId] += 1
41        video = self.videoIdToVideo[videoId]
42        duration = min(endMinute, len(video) - 1) - startMinute + 1
43        return video[startMinute:startMinute + duration]
44
45    def like(self, videoId: int) -> None:
46        if videoId in self.videoIdToVideo:
47            self.videoIdToLikes[videoId] += 1
48
49    def dislike(self, videoId: int) -> None:
50        if videoId in self.videoIdToVideo:
51            self.videoIdToDislikes[videoId] += 1
52
53    def getLikesAndDislikes(self, videoId: int) -> list[int]:
54        return [self.videoIdToLikes[videoId], self.videoIdToDislikes[videoId]] if videoId in self.videoIdToVideo else [-1]
55
56    def getViews(self, videoId: int) -> int:
57        return self.videoIdToViews[videoId] if videoId in self.videoIdToVideo else -1

Time Complexity

The time complexity for each operation in the video sharing platform is O(1) or O(logN) depending on the underlying implementation of the priority queue and maps. Since we are using default data structures available in Python, the overall time complexity is quite optimal for each operation.## JavaScript Solution

1
2javascript
3class VideoSharingPlatform {
4    constructor() {
5        this.currVideoId = 0;
6        this.usedIds = new PriorityQueue();
7        this.videoIdToVideo = new Map();
8        this.videoIdToViews = new Map();
9        this.videoIdToLikes = new Map();
10        this.videoIdToDislikes = new Map();
11    }
12
13    getVideoId() {
14        if (this.usedIds.isEmpty()) {
15            const videoId = this.currVideoId;
16            this.currVideoId += 1;
17            return videoId;
18        } else {
19            return this.usedIds.pop();
20        }
21    }
22
23    upload(video) {
24        const videoId = this.getVideoId();
25        this.videoIdToVideo.set(videoId, video);
26        return videoId;
27    }
28
29    remove(videoId) {
30        if (this.videoIdToVideo.has(videoId)) {
31            this.usedIds.push(videoId);
32            this.videoIdToVideo.delete(videoId);
33            this.videoIdToViews.delete(videoId);
34            this.videoIdToLikes.delete(videoId);
35            this.videoIdToDislikes.delete(videoId);
36        }
37    }
38
39    watch(videoId, startMinute, endMinute) {
40        if (!this.videoIdToVideo.has(videoId)) {
41            return "-1";
42        }
43        this.videoIdToViews.set(videoId, (this.videoIdToViews.get(videoId) || 0) + 1);
44        const video = this.videoIdToVideo.get(videoId);;
45        const duration = Math.min(endMinute, video.length - 1) - startMinute + 1;
46        return video.slice(startMinute, startMinute + duration);
47    }
48
49    like(videoId) {
50        if (this.videoIdToVideo.has(videoId)) {
51            this.videoIdToLikes.set(videoId, (this.videoIdToLikes.get(videoId) || 0) + 1);
52        }
53    }
54
55    unlike(videoId) {
56        if (this.videoIdToVideo.has(videoId)) {
57            this.videoIdToDislikes.set(videoId, (this.videoIdToDislikes.get(videoId) || 0) + 1);
58        }
59    }
60
61    getLikesAndDislikes(videoId) {
62        if (this.videoIdToVideo.has(videoId)) {
63            return [this.videoIdToLikes.get(videoId) || 0, this.videoIdToDislikes.get(videoId) || 0];
64        } else {
65            return [-1];
66        }
67    }
68
69    getViews(videoId) {
70        return this.videoIdToViews.get(videoId) || -1;
71    }
72}

Java Solution

1
2java
3import java.util.*;
4
5public class VideoSharingPlatform {
6    private int currVideoId;
7    private PriorityQueue<Integer> usedIds;
8    private Map<Integer, String> videoIdToVideo;
9    private Map<Integer, Integer> videoIdToViews;
10    private Map<Integer, Integer> videoIdToLikes;
11    private Map<Integer, Integer> videoIdToDislikes;
12
13    public VideoSharingPlatform() {
14        currVideoId = 0;
15        usedIds = new PriorityQueue<>();
16        videoIdToVideo = new HashMap<>();
17        videoIdToViews = new HashMap<>();
18        videoIdToLikes = new HashMap<>();
19        videoIdToDislikes = new HashMap<>();
20    }
21
22    public int getVideoId() {
23        if (usedIds.isEmpty()) {
24            return currVideoId++;
25        } else {
26            return usedIds.poll();
27        }
28    }
29
30    public int upload(String video) {
31        int videoId = getVideoId();
32        videoIdToVideo.put(videoId, video);
33        return videoId;
34    }
35
36    public void remove(int videoId) {
37        if (videoIdToVideo.containsKey(videoId)) {
38            usedIds.add(videoId);
39            videoIdToVideo.remove(videoId);
40            videoIdToViews.remove(videoId);
41            videoIdToLikes.remove(videoId);
42            videoIdToDislikes.remove(videoId);
43        }
44    }
45
46    public String watch(int videoId, int startMinute, int endMinute) {
47        if (!videoIdToVideo.containsKey(videoId)) {
48            return "-1";
49        }
50        videoIdToViews.put(videoId, videoIdToViews.getOrDefault(videoId, 0) + 1);
51        String video = videoIdToVideo.get(videoId);
52        int duration = Math.min(endMinute, video.length() - 1) - startMinute + 1;
53        return video.substring(startMinute, startMinute + duration);
54    }
55
56    public void like(int videoId) {
57        if (videoIdToVideo.containsKey(videoId)) {
58            videoIdToLikes.put(videoId, videoIdToLikes.getOrDefault(videoId, 0) + 1);
59        }
60    }
61
62    public void unlike(int videoId) {
63        if (videoIdToVideo.containsKey(videoId)) {
64            videoIdToDislikes.put(videoId, videoIdToDislikes.getOrDefault(videoId, 0) + 1);
65        }
66    }
67
68    public int[] getLikesAndDislikes(int videoId) {
69        if (videoIdToVideo.containsKey(videoId)) {
70            int[] result = new int[2];
71            result[0] = videoIdToLikes.getOrDefault(videoId, 0);
72            result[1] = videoIdToDislikes.getOrDefault(videoId, 0);
73            return result;
74        } else {
75            return new int[]{-1};
76        }
77    }
78
79    public int getViews(int videoId) {
80        return videoIdToViews.getOrDefault(videoId, -1);
81    }
82}

Time Complexity

The time complexity for each operation in the video sharing platform is O(1) or O(logN) depending on the underlying implementation of the priority queue and maps. In all the solutions above (Python, JavaScript, and Java), we are using default data structures available in these languages, so the overall time complexity is quite optimal for each operation.


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫