Design Movie Rental System

Hard
Watch on YouTube ↗

Solution

class MovieRentingSystem {
    // T.C. = O(nlogn)
    // S.C. = O(n)

    class MovieCopy {
        int shop, movie, price;
        MovieCopy(int shop, int movie, int price) {
            this.shop = shop;
            this.movie = movie;
            this.price = price;
        }
    }

    // Data structure initialization
    private Map<Integer, TreeSet<MovieCopy>> movieToCopies;  // unrented movies
    private Map<String, MovieCopy> shopMovieMap;         // mapping for uniquely identifying moviecopy object    
    private TreeSet<MovieCopy> rented;   

    public MovieRentingSystem(int n, int[][] entries) {
        movieToCopies = new HashMap<>();
        shopMovieMap = new HashMap<>();
        // Onlogn
        rented = new TreeSet<>((a, b) -> {
            if (a.price != b.price) return a.price - b.price;
            if (a.shop != b.shop) return a.shop - b.shop;
            return a.movie - b.movie;
        });

        for (int[] e : entries) {
            int shop = e[0], movie = e[1], price = e[2];
            MovieCopy copy = new MovieCopy(shop, movie, price);

            shopMovieMap.put(shop + ":" + movie, copy);
            movieToCopies.putIfAbsent(movie, new TreeSet<>(
                (a, b) -> (a.price != b.price) ? a.price - b.price : a.shop - b.shop
            ));
            movieToCopies.get(movie).add(copy);
        }
    }

    /*
    1 - [obj2[1,1,4] <--> obj1[0,1,5]<--> obj3[2,1,5]], 
    2 - [obj4[0,2,6] <--> obj5[2,2,7]]
    */
    
    public List<Integer> search(int movie) {
        // O(1)
        List<Integer> result = new ArrayList<>();
        if (!movieToCopies.containsKey(movie)) return result;

        Iterator<MovieCopy> it = movieToCopies.get(movie).iterator();
        for (int count = 0; it.hasNext() && count < 5; count++) {
            result.add(it.next().shop); // [1,0,2]
        }
        return result;
    }
    
    public void rent(int shop, int movie) {
        // O(logn)
        MovieCopy copy = shopMovieMap.get(shop + ":" + movie);
        movieToCopies.get(movie).remove(copy); // unrented
        rented.add(copy); // add
    }
    
    public void drop(int shop, int movie) {
        // O(logn)
        MovieCopy copy = shopMovieMap.get(shop + ":" + movie);
        rented.remove(copy);
        movieToCopies.get(movie).add(copy);
    }
    
    public List<List<Integer>> report() {
        // O(1)
        // rented [sorted values of moviecopies objects]
        List<List<Integer>> result = new ArrayList<>();
        Iterator<MovieCopy> it = rented.iterator();
        for (int count = 0; it.hasNext() && count < 5; count++) {
            MovieCopy c = it.next();
            result.add(Arrays.asList(c.shop, c.movie));
        }
        return result;
    }
}

/**
 * Your MovieRentingSystem object will be instantiated and called as such:
 * MovieRentingSystem obj = new MovieRentingSystem(n, entries);
 * List<Integer> param_1 = obj.search(movie);
 * obj.rent(shop,movie);
 * obj.drop(shop,movie);
 * List<List<Integer>> param_4 = obj.report();

MovieCopies

| Shop | Movie | Price |
| ---- | ----- | ----- |
| 0    | 1     | 5     |
| 0    | 2     | 6     |
| 1    | 1     | 4     |
| 2    | 1     | 5     |
| 2    | 2     | 7     |

Search: cheapest 5 shops with unrented copies of given movie

MovieCopy [movieid, shopid, price]

[Data Structure: Movie --> [list of all MovieCopies sorted on the basis of price i.e. a Treeset type of ds]]

------------movieCopies MAP---------------
1 - [obj2[1,1,4] <--> obj1[0,1,5]<--> obj3[2,1,5]], [1,0,2]
2 - [obj4[0,2,6] <--> obj5[2,2,7]]

Rent: Renting an unrented movie from a given shop
(1,1)
[Data Structure: collection of all rented moviecopies (set)
but we need to find MovieCopy object from previous map 
so another Data structure: [shop+movie]-->MovieCopy for unique object saving]
RentedSet - [obj2]
ShopToMovieCopy MAP
"0+1" --> obj1
"1+1" --> obj2
"2+1" --> obj3
"0+2" --> obj4
"2+2" --> obj5

Drop: unrenting, dropping off the movie
[removing from rented set, and adding to movieCopies map]

Report: cheapest five rented movies sorted --> price --> shopid --> movieid
[make use of rented set, but make it sorted --> so treeset]

[1--2--3--4--5--6--7] - rentedset
 */