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 a video. Return the videoId associated with the video.
  • void remove(int videoId) If there is a video associated with videoId, remove the video.
  • String watch(int videoId, int startMinute, int endMinute) If there is a video associated with videoId, increase the number of views on the video by 1 and return the substring of the video string starting at startMinute and ending at min(endMinute, video.length - 1``) (inclusive). Otherwise, return "-1".
  • void like(int videoId) Increases the number of likes on the video associated with videoId by 1 if there is a video associated with videoId.
  • void dislike(int videoId) Increases the number of dislikes on the video associated with videoId by 1 if there is a video associated with videoId.
  • int[] getLikesAndDislikes(int videoId) Return a 0-indexed integer array values of length 2 where values[0] is the number of likes and values[1] is the number of dislikes on the video associated with videoId. If there is no video associated with videoId, return [-1].
  • int getViews(int videoId) Return the number of views on the video associated with videoId, if there is no video associated with videoId, return -1.

Examples

Example 1:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
**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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
**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.length over all calls to upload does not exceed 105
  • video consists of digits.
  • 0 <= videoId <= 10^5
  • 0 <= startMinute < endMinute < 10^5
  • startMinute < video.length
  • The sum of endMinute - startMinute over all calls to watch does not exceed 105.
  • At most 105 calls 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

  1. Use a min heap to track available videoIds. If empty, use the next sequential id.
  2. Use a hash map to store video info: content, views, likes, dislikes for each videoId.
  3. For upload, assign the smallest available id, store the video, and return the id.
  4. For remove, delete the video and add its id to the heap.
  5. For watch, if the video exists, increment views and return the substring; else return “-1”.
  6. For like/dislike, increment the respective counter if the video exists.
  7. For getLikesAndDislikes, return [likes, dislikes] or [-1] if not found.
  8. For getViews, return views or -1 if not found.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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), where n is the number of videos stored.