From 58f702289308e8ddfee05be1c27b0122f79a5ad2 Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Sun, 21 Sep 2025 09:41:23 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.1912 No.1912.Design Movie Rental System --- .../1912.Design Movie Rental System/README.md | 306 +++++++++++++++++- .../README_EN.md | 306 +++++++++++++++++- .../Solution.cpp | 67 ++++ .../Solution.go | 100 ++++++ .../Solution.java | 80 +++++ .../Solution.py | 24 +- 6 files changed, 851 insertions(+), 32 deletions(-) create mode 100644 solution/1900-1999/1912.Design Movie Rental System/Solution.cpp create mode 100644 solution/1900-1999/1912.Design Movie Rental System/Solution.go create mode 100644 solution/1900-1999/1912.Design Movie Rental System/Solution.java diff --git a/solution/1900-1999/1912.Design Movie Rental System/README.md b/solution/1900-1999/1912.Design Movie Rental System/README.md index 696e109000383..73758b10a7aaf 100644 --- a/solution/1900-1999/1912.Design Movie Rental System/README.md +++ b/solution/1900-1999/1912.Design Movie Rental System/README.md @@ -87,7 +87,25 @@ movieRentingSystem.search(2); // 返回 [0, 1] 。商店 0 和 1 有未借出 -### 方法一 +### 方法一:有序集合 + +我们定义一个有序集合 $\textit{available}$,其中 $\textit{available}[movie]$ 存储所有未借出的电影 $movie$ 的商店列表,列表中的元素为 $(\textit{price}, \textit{shop})$,并按照 $\textit{price}$ 升序排序,如果 $\textit{price}$ 相同,则按照 $\textit{shop}$ 升序排序。 + +另外定义一个哈希表 $\textit{price\_map}$,其中 $\textit{price\_map}[f(\textit{shop}, \textit{movie})]$ 存储商店 $\textit{shop}$ 中电影 $\textit{movie}$ 的租借价格。 + +我们还定义一个有序集合 $\textit{rented}$,其中存储所有已借出的电影,元素为 $(\textit{price}, \textit{shop}, \textit{movie})$,并按照 $\textit{price}$ 升序排序,如果 $\textit{price}$ 相同,则按照 $\textit{shop}$ 升序排序,如果 $\textit{shop}$ 也相同,则按照 $\textit{movie}$ 升序排序。 + +对于 $\text{MovieRentingSystem}(n, \text{entries})$ 操作,我们遍历 $\text{entries}$,将每个商店的电影信息加入到 $\textit{available}$ 和 $\textit{price\_map}$ 中。时间复杂度为 $O(m \log m)$,其中 $m$ 是 $\text{entries}$ 的长度。 + +对于 $\text{search}(\text{movie})$ 操作,我们返回 $\textit{available}[\text{movie}]$ 中前 5 个商店的编号。时间复杂度为 $O(1)$。 + +对于 $\text{rent}(\text{shop}, \text{movie})$ 操作,我们从 $\textit{available}[\text{movie}]$ 中移除 $(\textit{price}, \textit{shop})$,并将 $(\textit{price}, \textit{shop}, \textit{movie})$ 加入到 $\textit{rented}$ 中。时间复杂度为 $O(\log m)$。 + +对于 $\text{drop}(\text{shop}, \text{movie})$ 操作,我们从 $\textit{rented}$ 中移除 $(\textit{price}, \textit{shop}, \textit{movie})$,并将 $(\textit{price}, \textit{shop})$ 加入到 $\textit{available}[\text{movie}]$ 中。时间复杂度为 $O(\log m)$。 + +对于 $\text{report}()$ 操作,我们返回 $\textit{rented}$ 中前 5 个已借出电影的商店编号和电影编号。时间复杂度为 $O(1)$。 + +空间复杂度为 $O(m)$。其中 $m$ 是 $\text{entries}$ 的长度。 @@ -95,30 +113,34 @@ movieRentingSystem.search(2); // 返回 [0, 1] 。商店 0 和 1 有未借出 ```python class MovieRentingSystem: + def __init__(self, n: int, entries: List[List[int]]): - self.unrented = collections.defaultdict(SortedList) # {movie: (price, shop)} - self.shopAndMovieToPrice = {} # {(shop, movie): price} - self.rented = SortedList() # (price, shop, movie) + self.available = defaultdict(lambda: SortedList()) + self.price_map = {} for shop, movie, price in entries: - self.unrented[movie].add((price, shop)) - self.shopAndMovieToPrice[(shop, movie)] = price + self.available[movie].add((price, shop)) + self.price_map[self.f(shop, movie)] = price + self.rented = SortedList() def search(self, movie: int) -> List[int]: - return [shop for _, shop in self.unrented[movie][:5]] + return [shop for _, shop in self.available[movie][:5]] def rent(self, shop: int, movie: int) -> None: - price = self.shopAndMovieToPrice[(shop, movie)] - self.unrented[movie].remove((price, shop)) + price = self.price_map[self.f(shop, movie)] + self.available[movie].remove((price, shop)) self.rented.add((price, shop, movie)) def drop(self, shop: int, movie: int) -> None: - price = self.shopAndMovieToPrice[(shop, movie)] - self.unrented[movie].add((price, shop)) + price = self.price_map[self.f(shop, movie)] self.rented.remove((price, shop, movie)) + self.available[movie].add((price, shop)) def report(self) -> List[List[int]]: return [[shop, movie] for _, shop, movie in self.rented[:5]] + def f(self, shop: int, movie: int) -> int: + return shop << 30 | movie + # Your MovieRentingSystem object will be instantiated and called as such: # obj = MovieRentingSystem(n, entries) @@ -128,6 +150,268 @@ class MovieRentingSystem: # param_4 = obj.report() ``` +#### Java + +```java +class MovieRentingSystem { + private Map> available = new HashMap<>(); + private Map priceMap = new HashMap<>(); + private TreeSet rented = new TreeSet<>((a, b) -> { + if (a[0] != b[0]) { + return a[0] - b[0]; + } + if (a[1] != b[1]) { + return a[1] - b[1]; + } + return a[2] - b[2]; + }); + + public MovieRentingSystem(int n, int[][] entries) { + for (int[] entry : entries) { + int shop = entry[0], movie = entry[1], price = entry[2]; + available + .computeIfAbsent(movie, k -> new TreeSet<>((a, b) -> { + if (a[0] != b[0]) { + return a[0] - b[0]; + } + return a[1] - b[1]; + })) + .add(new int[] {price, shop}); + priceMap.put(f(shop, movie), price); + } + } + + public List search(int movie) { + List res = new ArrayList<>(); + if (!available.containsKey(movie)) { + return res; + } + int cnt = 0; + for (int[] item : available.get(movie)) { + res.add(item[1]); + if (++cnt == 5) { + break; + } + } + return res; + } + + public void rent(int shop, int movie) { + int price = priceMap.get(f(shop, movie)); + available.get(movie).remove(new int[] {price, shop}); + rented.add(new int[] {price, shop, movie}); + } + + public void drop(int shop, int movie) { + int price = priceMap.get(f(shop, movie)); + rented.remove(new int[] {price, shop, movie}); + available.get(movie).add(new int[] {price, shop}); + } + + public List> report() { + List> res = new ArrayList<>(); + int cnt = 0; + for (int[] item : rented) { + res.add(Arrays.asList(item[1], item[2])); + if (++cnt == 5) { + break; + } + } + return res; + } + + private long f(int shop, int movie) { + return ((long) shop << 30) | movie; + } +} + +/** + * Your MovieRentingSystem object will be instantiated and called as such: + * MovieRentingSystem obj = new MovieRentingSystem(n, entries); + * List param_1 = obj.search(movie); + * obj.rent(shop,movie); + * obj.drop(shop,movie); + * List> param_4 = obj.report(); + */ +``` + +#### C++ + +```cpp +class MovieRentingSystem { +private: + unordered_map>> available; // movie -> {(price, shop)} + unordered_map priceMap; + set> rented; // {(price, shop, movie)} + + long long f(int shop, int movie) { + return ((long long) shop << 30) | movie; + } + +public: + MovieRentingSystem(int n, vector>& entries) { + for (auto& e : entries) { + int shop = e[0], movie = e[1], price = e[2]; + available[movie].insert({price, shop}); + priceMap[f(shop, movie)] = price; + } + } + + vector search(int movie) { + vector res; + if (!available.count(movie)) { + return res; + } + int cnt = 0; + for (auto& [price, shop] : available[movie]) { + res.push_back(shop); + if (++cnt == 5) { + break; + } + } + return res; + } + + void rent(int shop, int movie) { + int price = priceMap[f(shop, movie)]; + available[movie].erase({price, shop}); + rented.insert({price, shop, movie}); + } + + void drop(int shop, int movie) { + int price = priceMap[f(shop, movie)]; + rented.erase({price, shop, movie}); + available[movie].insert({price, shop}); + } + + vector> report() { + vector> res; + int cnt = 0; + for (auto& [price, shop, movie] : rented) { + res.push_back({shop, movie}); + if (++cnt == 5) { + break; + } + } + return res; + } +}; + +/** + * Your MovieRentingSystem object will be instantiated and called as such: + * MovieRentingSystem* obj = new MovieRentingSystem(n, entries); + * vector param_1 = obj->search(movie); + * obj->rent(shop,movie); + * obj->drop(shop,movie); + * vector> param_4 = obj->report(); + */ +``` + +#### Go + +```go +type MovieRentingSystem struct { + available map[int]*treeset.Set // movie -> (price, shop) + priceMap map[int64]int + rented *treeset.Set // (price, shop, movie) +} + +func Constructor(n int, entries [][]int) MovieRentingSystem { + // comparator for (price, shop) + cmpAvail := func(a, b any) int { + x := a.([2]int) + y := b.([2]int) + if x[0] != y[0] { + return x[0] - y[0] + } + return x[1] - y[1] + } + // comparator for (price, shop, movie) + cmpRented := func(a, b any) int { + x := a.([3]int) + y := b.([3]int) + if x[0] != y[0] { + return x[0] - y[0] + } + if x[1] != y[1] { + return x[1] - y[1] + } + return x[2] - y[2] + } + + mrs := MovieRentingSystem{ + available: make(map[int]*treeset.Set), + priceMap: make(map[int64]int), + rented: treeset.NewWith(cmpRented), + } + + for _, e := range entries { + shop, movie, price := e[0], e[1], e[2] + if _, ok := mrs.available[movie]; !ok { + mrs.available[movie] = treeset.NewWith(cmpAvail) + } + mrs.available[movie].Add([2]int{price, shop}) + mrs.priceMap[f(shop, movie)] = price + } + + return mrs +} + +func (this *MovieRentingSystem) Search(movie int) []int { + res := []int{} + if _, ok := this.available[movie]; !ok { + return res + } + it := this.available[movie].Iterator() + it.Begin() + cnt := 0 + for it.Next() && cnt < 5 { + pair := it.Value().([2]int) + res = append(res, pair[1]) + cnt++ + } + return res +} + +func (this *MovieRentingSystem) Rent(shop int, movie int) { + price := this.priceMap[f(shop, movie)] + this.available[movie].Remove([2]int{price, shop}) + this.rented.Add([3]int{price, shop, movie}) +} + +func (this *MovieRentingSystem) Drop(shop int, movie int) { + price := this.priceMap[f(shop, movie)] + this.rented.Remove([3]int{price, shop, movie}) + this.available[movie].Add([2]int{price, shop}) +} + +func (this *MovieRentingSystem) Report() [][]int { + res := [][]int{} + it := this.rented.Iterator() + it.Begin() + cnt := 0 + for it.Next() && cnt < 5 { + t := it.Value().([3]int) + res = append(res, []int{t[1], t[2]}) + cnt++ + } + return res +} + +func f(shop, movie int) int64 { + return (int64(shop) << 30) | int64(movie) +} + +/** + * Your MovieRentingSystem object will be instantiated and called as such: + * obj := Constructor(n, entries); + * param_1 := obj.Search(movie); + * obj.Rent(shop,movie); + * obj.Drop(shop,movie); + * param_4 := obj.Report(); + */ +``` + diff --git a/solution/1900-1999/1912.Design Movie Rental System/README_EN.md b/solution/1900-1999/1912.Design Movie Rental System/README_EN.md index b4b3e8c5c2ef4..e402445109fc1 100644 --- a/solution/1900-1999/1912.Design Movie Rental System/README_EN.md +++ b/solution/1900-1999/1912.Design Movie Rental System/README_EN.md @@ -85,7 +85,25 @@ movieRentingSystem.search(2); // return [0, 1]. Movies of ID 2 are unrented at -### Solution 1 +### Solution 1: Ordered Set + +We define an ordered set $\textit{available}$, where $\textit{available}[movie]$ stores a list of all shops that have not rented out the movie $movie$. Each element in the list is $(\textit{price}, \textit{shop})$, sorted in ascending order by $\textit{price}$, and if prices are equal, by $\textit{shop}$ in ascending order. + +Additionally, we define a hash map $\textit{price\_map}$, where $\textit{price\_map}[f(\textit{shop}, \textit{movie})]$ stores the rental price of movie $\textit{movie}$ in shop $\textit{shop}$. + +We also define an ordered set $\textit{rented}$, which stores all rented movies as $(\textit{price}, \textit{shop}, \textit{movie})$, sorted in ascending order by $\textit{price}$, then by $\textit{shop}$, and if both are equal, by $\textit{movie}$. + +For the $\text{MovieRentingSystem}(n, \text{entries})$ operation, we iterate through $\text{entries}$ and add each shop's movie information to both $\textit{available}$ and $\textit{price\_map}$. The time complexity is $O(m \log m)$, where $m$ is the length of $\text{entries}$. + +For the $\text{search}(\text{movie})$ operation, we return the shop IDs of the first 5 shops in $\textit{available}[\text{movie}]$. The time complexity is $O(1)$. + +For the $\text{rent}(\text{shop}, \text{movie})$ operation, we remove $(\textit{price}, \textit{shop})$ from $\textit{available}[\text{movie}]$ and add $(\textit{price}, \textit{shop}, \textit{movie})$ to $\textit{rented}$. The time complexity is $O(\log m)$. + +For the $\text{drop}(\text{shop}, \text{movie})$ operation, we remove $(\textit{price}, \textit{shop}, \textit{movie})$ from $\textit{rented}$ and add $(\textit{price}, \textit{shop})$ back to $\textit{available}[\text{movie}]$. The time complexity is $O(\log m)$. + +For the $\text{report}()$ operation, we return the shop and movie IDs of the first 5 rented movies in $\textit{rented}$. The time complexity is $O(1)$. + +The space complexity is $O(m)$, where $m$ is the length of $\text{entries}$. @@ -93,30 +111,34 @@ movieRentingSystem.search(2); // return [0, 1]. Movies of ID 2 are unrented at ```python class MovieRentingSystem: + def __init__(self, n: int, entries: List[List[int]]): - self.unrented = collections.defaultdict(SortedList) # {movie: (price, shop)} - self.shopAndMovieToPrice = {} # {(shop, movie): price} - self.rented = SortedList() # (price, shop, movie) + self.available = defaultdict(lambda: SortedList()) + self.price_map = {} for shop, movie, price in entries: - self.unrented[movie].add((price, shop)) - self.shopAndMovieToPrice[(shop, movie)] = price + self.available[movie].add((price, shop)) + self.price_map[self.f(shop, movie)] = price + self.rented = SortedList() def search(self, movie: int) -> List[int]: - return [shop for _, shop in self.unrented[movie][:5]] + return [shop for _, shop in self.available[movie][:5]] def rent(self, shop: int, movie: int) -> None: - price = self.shopAndMovieToPrice[(shop, movie)] - self.unrented[movie].remove((price, shop)) + price = self.price_map[self.f(shop, movie)] + self.available[movie].remove((price, shop)) self.rented.add((price, shop, movie)) def drop(self, shop: int, movie: int) -> None: - price = self.shopAndMovieToPrice[(shop, movie)] - self.unrented[movie].add((price, shop)) + price = self.price_map[self.f(shop, movie)] self.rented.remove((price, shop, movie)) + self.available[movie].add((price, shop)) def report(self) -> List[List[int]]: return [[shop, movie] for _, shop, movie in self.rented[:5]] + def f(self, shop: int, movie: int) -> int: + return shop << 30 | movie + # Your MovieRentingSystem object will be instantiated and called as such: # obj = MovieRentingSystem(n, entries) @@ -126,6 +148,268 @@ class MovieRentingSystem: # param_4 = obj.report() ``` +#### Java + +```java +class MovieRentingSystem { + private Map> available = new HashMap<>(); + private Map priceMap = new HashMap<>(); + private TreeSet rented = new TreeSet<>((a, b) -> { + if (a[0] != b[0]) { + return a[0] - b[0]; + } + if (a[1] != b[1]) { + return a[1] - b[1]; + } + return a[2] - b[2]; + }); + + public MovieRentingSystem(int n, int[][] entries) { + for (int[] entry : entries) { + int shop = entry[0], movie = entry[1], price = entry[2]; + available + .computeIfAbsent(movie, k -> new TreeSet<>((a, b) -> { + if (a[0] != b[0]) { + return a[0] - b[0]; + } + return a[1] - b[1]; + })) + .add(new int[] {price, shop}); + priceMap.put(f(shop, movie), price); + } + } + + public List search(int movie) { + List res = new ArrayList<>(); + if (!available.containsKey(movie)) { + return res; + } + int cnt = 0; + for (int[] item : available.get(movie)) { + res.add(item[1]); + if (++cnt == 5) { + break; + } + } + return res; + } + + public void rent(int shop, int movie) { + int price = priceMap.get(f(shop, movie)); + available.get(movie).remove(new int[] {price, shop}); + rented.add(new int[] {price, shop, movie}); + } + + public void drop(int shop, int movie) { + int price = priceMap.get(f(shop, movie)); + rented.remove(new int[] {price, shop, movie}); + available.get(movie).add(new int[] {price, shop}); + } + + public List> report() { + List> res = new ArrayList<>(); + int cnt = 0; + for (int[] item : rented) { + res.add(Arrays.asList(item[1], item[2])); + if (++cnt == 5) { + break; + } + } + return res; + } + + private long f(int shop, int movie) { + return ((long) shop << 30) | movie; + } +} + +/** + * Your MovieRentingSystem object will be instantiated and called as such: + * MovieRentingSystem obj = new MovieRentingSystem(n, entries); + * List param_1 = obj.search(movie); + * obj.rent(shop,movie); + * obj.drop(shop,movie); + * List> param_4 = obj.report(); + */ +``` + +#### C++ + +```cpp +class MovieRentingSystem { +private: + unordered_map>> available; // movie -> {(price, shop)} + unordered_map priceMap; + set> rented; // {(price, shop, movie)} + + long long f(int shop, int movie) { + return ((long long) shop << 30) | movie; + } + +public: + MovieRentingSystem(int n, vector>& entries) { + for (auto& e : entries) { + int shop = e[0], movie = e[1], price = e[2]; + available[movie].insert({price, shop}); + priceMap[f(shop, movie)] = price; + } + } + + vector search(int movie) { + vector res; + if (!available.count(movie)) { + return res; + } + int cnt = 0; + for (auto& [price, shop] : available[movie]) { + res.push_back(shop); + if (++cnt == 5) { + break; + } + } + return res; + } + + void rent(int shop, int movie) { + int price = priceMap[f(shop, movie)]; + available[movie].erase({price, shop}); + rented.insert({price, shop, movie}); + } + + void drop(int shop, int movie) { + int price = priceMap[f(shop, movie)]; + rented.erase({price, shop, movie}); + available[movie].insert({price, shop}); + } + + vector> report() { + vector> res; + int cnt = 0; + for (auto& [price, shop, movie] : rented) { + res.push_back({shop, movie}); + if (++cnt == 5) { + break; + } + } + return res; + } +}; + +/** + * Your MovieRentingSystem object will be instantiated and called as such: + * MovieRentingSystem* obj = new MovieRentingSystem(n, entries); + * vector param_1 = obj->search(movie); + * obj->rent(shop,movie); + * obj->drop(shop,movie); + * vector> param_4 = obj->report(); + */ +``` + +#### Go + +```go +type MovieRentingSystem struct { + available map[int]*treeset.Set // movie -> (price, shop) + priceMap map[int64]int + rented *treeset.Set // (price, shop, movie) +} + +func Constructor(n int, entries [][]int) MovieRentingSystem { + // comparator for (price, shop) + cmpAvail := func(a, b any) int { + x := a.([2]int) + y := b.([2]int) + if x[0] != y[0] { + return x[0] - y[0] + } + return x[1] - y[1] + } + // comparator for (price, shop, movie) + cmpRented := func(a, b any) int { + x := a.([3]int) + y := b.([3]int) + if x[0] != y[0] { + return x[0] - y[0] + } + if x[1] != y[1] { + return x[1] - y[1] + } + return x[2] - y[2] + } + + mrs := MovieRentingSystem{ + available: make(map[int]*treeset.Set), + priceMap: make(map[int64]int), + rented: treeset.NewWith(cmpRented), + } + + for _, e := range entries { + shop, movie, price := e[0], e[1], e[2] + if _, ok := mrs.available[movie]; !ok { + mrs.available[movie] = treeset.NewWith(cmpAvail) + } + mrs.available[movie].Add([2]int{price, shop}) + mrs.priceMap[f(shop, movie)] = price + } + + return mrs +} + +func (this *MovieRentingSystem) Search(movie int) []int { + res := []int{} + if _, ok := this.available[movie]; !ok { + return res + } + it := this.available[movie].Iterator() + it.Begin() + cnt := 0 + for it.Next() && cnt < 5 { + pair := it.Value().([2]int) + res = append(res, pair[1]) + cnt++ + } + return res +} + +func (this *MovieRentingSystem) Rent(shop int, movie int) { + price := this.priceMap[f(shop, movie)] + this.available[movie].Remove([2]int{price, shop}) + this.rented.Add([3]int{price, shop, movie}) +} + +func (this *MovieRentingSystem) Drop(shop int, movie int) { + price := this.priceMap[f(shop, movie)] + this.rented.Remove([3]int{price, shop, movie}) + this.available[movie].Add([2]int{price, shop}) +} + +func (this *MovieRentingSystem) Report() [][]int { + res := [][]int{} + it := this.rented.Iterator() + it.Begin() + cnt := 0 + for it.Next() && cnt < 5 { + t := it.Value().([3]int) + res = append(res, []int{t[1], t[2]}) + cnt++ + } + return res +} + +func f(shop, movie int) int64 { + return (int64(shop) << 30) | int64(movie) +} + +/** + * Your MovieRentingSystem object will be instantiated and called as such: + * obj := Constructor(n, entries); + * param_1 := obj.Search(movie); + * obj.Rent(shop,movie); + * obj.Drop(shop,movie); + * param_4 := obj.Report(); + */ +``` + diff --git a/solution/1900-1999/1912.Design Movie Rental System/Solution.cpp b/solution/1900-1999/1912.Design Movie Rental System/Solution.cpp new file mode 100644 index 0000000000000..da0c91e64c4e7 --- /dev/null +++ b/solution/1900-1999/1912.Design Movie Rental System/Solution.cpp @@ -0,0 +1,67 @@ +class MovieRentingSystem { +private: + unordered_map>> available; // movie -> {(price, shop)} + unordered_map priceMap; + set> rented; // {(price, shop, movie)} + + long long f(int shop, int movie) { + return ((long long) shop << 30) | movie; + } + +public: + MovieRentingSystem(int n, vector>& entries) { + for (auto& e : entries) { + int shop = e[0], movie = e[1], price = e[2]; + available[movie].insert({price, shop}); + priceMap[f(shop, movie)] = price; + } + } + + vector search(int movie) { + vector res; + if (!available.count(movie)) { + return res; + } + int cnt = 0; + for (auto& [price, shop] : available[movie]) { + res.push_back(shop); + if (++cnt == 5) { + break; + } + } + return res; + } + + void rent(int shop, int movie) { + int price = priceMap[f(shop, movie)]; + available[movie].erase({price, shop}); + rented.insert({price, shop, movie}); + } + + void drop(int shop, int movie) { + int price = priceMap[f(shop, movie)]; + rented.erase({price, shop, movie}); + available[movie].insert({price, shop}); + } + + vector> report() { + vector> res; + int cnt = 0; + for (auto& [price, shop, movie] : rented) { + res.push_back({shop, movie}); + if (++cnt == 5) { + break; + } + } + return res; + } +}; + +/** + * Your MovieRentingSystem object will be instantiated and called as such: + * MovieRentingSystem* obj = new MovieRentingSystem(n, entries); + * vector param_1 = obj->search(movie); + * obj->rent(shop,movie); + * obj->drop(shop,movie); + * vector> param_4 = obj->report(); + */ diff --git a/solution/1900-1999/1912.Design Movie Rental System/Solution.go b/solution/1900-1999/1912.Design Movie Rental System/Solution.go new file mode 100644 index 0000000000000..5c3442433b164 --- /dev/null +++ b/solution/1900-1999/1912.Design Movie Rental System/Solution.go @@ -0,0 +1,100 @@ +type MovieRentingSystem struct { + available map[int]*treeset.Set // movie -> (price, shop) + priceMap map[int64]int + rented *treeset.Set // (price, shop, movie) +} + +func Constructor(n int, entries [][]int) MovieRentingSystem { + // comparator for (price, shop) + cmpAvail := func(a, b any) int { + x := a.([2]int) + y := b.([2]int) + if x[0] != y[0] { + return x[0] - y[0] + } + return x[1] - y[1] + } + // comparator for (price, shop, movie) + cmpRented := func(a, b any) int { + x := a.([3]int) + y := b.([3]int) + if x[0] != y[0] { + return x[0] - y[0] + } + if x[1] != y[1] { + return x[1] - y[1] + } + return x[2] - y[2] + } + + mrs := MovieRentingSystem{ + available: make(map[int]*treeset.Set), + priceMap: make(map[int64]int), + rented: treeset.NewWith(cmpRented), + } + + for _, e := range entries { + shop, movie, price := e[0], e[1], e[2] + if _, ok := mrs.available[movie]; !ok { + mrs.available[movie] = treeset.NewWith(cmpAvail) + } + mrs.available[movie].Add([2]int{price, shop}) + mrs.priceMap[f(shop, movie)] = price + } + + return mrs +} + +func (this *MovieRentingSystem) Search(movie int) []int { + res := []int{} + if _, ok := this.available[movie]; !ok { + return res + } + it := this.available[movie].Iterator() + it.Begin() + cnt := 0 + for it.Next() && cnt < 5 { + pair := it.Value().([2]int) + res = append(res, pair[1]) + cnt++ + } + return res +} + +func (this *MovieRentingSystem) Rent(shop int, movie int) { + price := this.priceMap[f(shop, movie)] + this.available[movie].Remove([2]int{price, shop}) + this.rented.Add([3]int{price, shop, movie}) +} + +func (this *MovieRentingSystem) Drop(shop int, movie int) { + price := this.priceMap[f(shop, movie)] + this.rented.Remove([3]int{price, shop, movie}) + this.available[movie].Add([2]int{price, shop}) +} + +func (this *MovieRentingSystem) Report() [][]int { + res := [][]int{} + it := this.rented.Iterator() + it.Begin() + cnt := 0 + for it.Next() && cnt < 5 { + t := it.Value().([3]int) + res = append(res, []int{t[1], t[2]}) + cnt++ + } + return res +} + +func f(shop, movie int) int64 { + return (int64(shop) << 30) | int64(movie) +} + +/** + * Your MovieRentingSystem object will be instantiated and called as such: + * obj := Constructor(n, entries); + * param_1 := obj.Search(movie); + * obj.Rent(shop,movie); + * obj.Drop(shop,movie); + * param_4 := obj.Report(); + */ diff --git a/solution/1900-1999/1912.Design Movie Rental System/Solution.java b/solution/1900-1999/1912.Design Movie Rental System/Solution.java new file mode 100644 index 0000000000000..d0cdc4019c040 --- /dev/null +++ b/solution/1900-1999/1912.Design Movie Rental System/Solution.java @@ -0,0 +1,80 @@ +class MovieRentingSystem { + private Map> available = new HashMap<>(); + private Map priceMap = new HashMap<>(); + private TreeSet rented = new TreeSet<>((a, b) -> { + if (a[0] != b[0]) { + return a[0] - b[0]; + } + if (a[1] != b[1]) { + return a[1] - b[1]; + } + return a[2] - b[2]; + }); + + public MovieRentingSystem(int n, int[][] entries) { + for (int[] entry : entries) { + int shop = entry[0], movie = entry[1], price = entry[2]; + available + .computeIfAbsent(movie, k -> new TreeSet<>((a, b) -> { + if (a[0] != b[0]) { + return a[0] - b[0]; + } + return a[1] - b[1]; + })) + .add(new int[] {price, shop}); + priceMap.put(f(shop, movie), price); + } + } + + public List search(int movie) { + List res = new ArrayList<>(); + if (!available.containsKey(movie)) { + return res; + } + int cnt = 0; + for (int[] item : available.get(movie)) { + res.add(item[1]); + if (++cnt == 5) { + break; + } + } + return res; + } + + public void rent(int shop, int movie) { + int price = priceMap.get(f(shop, movie)); + available.get(movie).remove(new int[] {price, shop}); + rented.add(new int[] {price, shop, movie}); + } + + public void drop(int shop, int movie) { + int price = priceMap.get(f(shop, movie)); + rented.remove(new int[] {price, shop, movie}); + available.get(movie).add(new int[] {price, shop}); + } + + public List> report() { + List> res = new ArrayList<>(); + int cnt = 0; + for (int[] item : rented) { + res.add(Arrays.asList(item[1], item[2])); + if (++cnt == 5) { + break; + } + } + return res; + } + + private long f(int shop, int movie) { + return ((long) shop << 30) | movie; + } +} + +/** + * Your MovieRentingSystem object will be instantiated and called as such: + * MovieRentingSystem obj = new MovieRentingSystem(n, entries); + * List param_1 = obj.search(movie); + * obj.rent(shop,movie); + * obj.drop(shop,movie); + * List> param_4 = obj.report(); + */ diff --git a/solution/1900-1999/1912.Design Movie Rental System/Solution.py b/solution/1900-1999/1912.Design Movie Rental System/Solution.py index fe1d482225471..a8dcc6ac99086 100644 --- a/solution/1900-1999/1912.Design Movie Rental System/Solution.py +++ b/solution/1900-1999/1912.Design Movie Rental System/Solution.py @@ -1,28 +1,32 @@ class MovieRentingSystem: + def __init__(self, n: int, entries: List[List[int]]): - self.unrented = collections.defaultdict(SortedList) # {movie: (price, shop)} - self.shopAndMovieToPrice = {} # {(shop, movie): price} - self.rented = SortedList() # (price, shop, movie) + self.available = defaultdict(lambda: SortedList()) + self.price_map = {} for shop, movie, price in entries: - self.unrented[movie].add((price, shop)) - self.shopAndMovieToPrice[(shop, movie)] = price + self.available[movie].add((price, shop)) + self.price_map[self.f(shop, movie)] = price + self.rented = SortedList() def search(self, movie: int) -> List[int]: - return [shop for _, shop in self.unrented[movie][:5]] + return [shop for _, shop in self.available[movie][:5]] def rent(self, shop: int, movie: int) -> None: - price = self.shopAndMovieToPrice[(shop, movie)] - self.unrented[movie].remove((price, shop)) + price = self.price_map[self.f(shop, movie)] + self.available[movie].remove((price, shop)) self.rented.add((price, shop, movie)) def drop(self, shop: int, movie: int) -> None: - price = self.shopAndMovieToPrice[(shop, movie)] - self.unrented[movie].add((price, shop)) + price = self.price_map[self.f(shop, movie)] self.rented.remove((price, shop, movie)) + self.available[movie].add((price, shop)) def report(self) -> List[List[int]]: return [[shop, movie] for _, shop, movie in self.rented[:5]] + def f(self, shop: int, movie: int) -> int: + return shop << 30 | movie + # Your MovieRentingSystem object will be instantiated and called as such: # obj = MovieRentingSystem(n, entries)