Problem
Problem ID: 1912
Title: Design Movie Rental System
Difficulty: Hard
Thoughts
This problem is not very hard to solve but it requires very careful state management. I found it very useful to write in comments what the corresponding index/key in the DS represents and writing the steps that will be required for each step.
My solution manages to get accepted but IMO it is not an elegant solution. Looking through the discussion it seems that there is no elegant solution to this problem.
Solution
We can reduce the problem to essentially, finding the cheapest 5 unrented movie-copy for a given movie and the cheapest 5 rented movie-copy for all movies.
To solve this problem we will maintain three data structures:
m_rented_movies
: A sorted list of all moviesreport()
: return the first 5 elementsrent(int shop_id, int movie_id)
: Add{price, shop_id, movie_id}
drop(int shop_id, int movie_id)
: Erase{price, shop_id, movie_id}
m_unrented_movies
: A map of movie id to a sorted list of unrented movie-copy of a shopsearch(int movie_id)
: return the first 5 elements in the sorted list ofmovie_id
rent(int shop_id, int movie_id)
: Remove{price, shop_id}
for the sorted list ofmovie_id
drop(int shop_id, int movie_id)
: Add{price, shop_id}
for the sorted list ofmovie_id
m_shop_movies
: A 2D map to query the price of a movie-copy for a given shop- Initialize during construction
Implementation
class MovieRentingSystem {
public:
// [[price,shop_id, movie_id]]
set<vector<int>> m_rented_movies;
// shop_movies[shop_id][movie_id] = price
unordered_map<int,unordered_map<int,int>> m_shop_movies;
// m_unrented_movies[movie_id] = [<price, shop_id>]
unordered_map<int, set<pair<int, int>>> m_unrented_movies;
MovieRentingSystem(int n, vector<vector<int>>& entries) {
for (const vector<int>& entry : entries) {
int shop_id = entry[0];
int movie_id = entry[1];
int price = entry[2];
m_unrented_movies[movie_id].insert({price, shop_id});
m_shop_movies[shop_id][movie_id] = price;
}
}
vector<int> search(int movie_id) {
// return the first 5 in m_unrented_movies[movie_id]
set<pair<int,int>>& unrented = m_unrented_movies[movie_id];
vector<int> shop_ids;
for (auto it = unrented.begin(); it != unrented.end() && shop_ids.size() < 5; it++) {
shop_ids.emplace_back(it->second);
}
return shop_ids;
}
void rent(int shop_id, int movie_id) {
int price = m_shop_movies[shop_id][movie_id];
// remove <price, shop_id> from m_unrented_movies[movie_id]
auto it = m_unrented_movies[movie_id].find({price, shop_id});
assert(it != m_unrented_movies[movie_id].end());
m_unrented_movies[movie_id].erase(it);
// add <price, shop_id, movie_id> to m_rented_movies
m_rented_movies.insert({price, shop_id, movie_id});
}
void drop(int shop_id, int movie_id) {
int price = m_shop_movies[shop_id][movie_id];
// remove <price, shop_id, movie_id> from m_rented_movies
auto it = m_rented_movies.find({price, shop_id, movie_id});
assert(it != m_rented_movies.end());
m_rented_movies.erase(it);
// add <price, shop_id> to m_unrented_movies[moved_id]
m_unrented_movies[movie_id].insert({price, shop_id});
}
vector<vector<int>> report() {
// return the first 4 in m_rented_movies
vector<vector<int>> movies;
for (auto it = m_rented_movies.begin(); it != m_rented_movies.end() && movies.size() < 5; it++) {
vector<int> movie = *it;
movies.push_back({movie[1], movie[2]});
}
return movies;
}
};