Skip to content

Commit 246946f

Browse files
authored
feat: add solutions to lc problem: No.1912 (doocs#4735)
No.1912.Design Movie Rental System
1 parent 5944c37 commit 246946f

File tree

6 files changed

+851
-32
lines changed

6 files changed

+851
-32
lines changed

solution/1900-1999/1912.Design Movie Rental System/README.md

Lines changed: 295 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,38 +87,60 @@ movieRentingSystem.search(2); // 返回 [0, 1] 。商店 0 和 1 有未借出
8787

8888
<!-- solution:start -->
8989

90-
### 方法一
90+
### 方法一:有序集合
91+
92+
我们定义一个有序集合 $\textit{available}$,其中 $\textit{available}[movie]$ 存储所有未借出的电影 $movie$ 的商店列表,列表中的元素为 $(\textit{price}, \textit{shop})$,并按照 $\textit{price}$ 升序排序,如果 $\textit{price}$ 相同,则按照 $\textit{shop}$ 升序排序。
93+
94+
另外定义一个哈希表 $\textit{price\_map}$,其中 $\textit{price\_map}[f(\textit{shop}, \textit{movie})]$ 存储商店 $\textit{shop}$ 中电影 $\textit{movie}$ 的租借价格。
95+
96+
我们还定义一个有序集合 $\textit{rented}$,其中存储所有已借出的电影,元素为 $(\textit{price}, \textit{shop}, \textit{movie})$,并按照 $\textit{price}$ 升序排序,如果 $\textit{price}$ 相同,则按照 $\textit{shop}$ 升序排序,如果 $\textit{shop}$ 也相同,则按照 $\textit{movie}$ 升序排序。
97+
98+
对于 $\text{MovieRentingSystem}(n, \text{entries})$ 操作,我们遍历 $\text{entries}$,将每个商店的电影信息加入到 $\textit{available}$ 和 $\textit{price\_map}$ 中。时间复杂度为 $O(m \log m)$,其中 $m$ 是 $\text{entries}$ 的长度。
99+
100+
对于 $\text{search}(\text{movie})$ 操作,我们返回 $\textit{available}[\text{movie}]$ 中前 5 个商店的编号。时间复杂度为 $O(1)$。
101+
102+
对于 $\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)$。
103+
104+
对于 $\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)$。
105+
106+
对于 $\text{report}()$ 操作,我们返回 $\textit{rented}$ 中前 5 个已借出电影的商店编号和电影编号。时间复杂度为 $O(1)$。
107+
108+
空间复杂度为 $O(m)$。其中 $m$ 是 $\text{entries}$ 的长度。
91109

92110
<!-- tabs:start -->
93111

94112
#### Python3
95113

96114
```python
97115
class MovieRentingSystem:
116+
98117
def __init__(self, n: int, entries: List[List[int]]):
99-
self.unrented = collections.defaultdict(SortedList) # {movie: (price, shop)}
100-
self.shopAndMovieToPrice = {} # {(shop, movie): price}
101-
self.rented = SortedList() # (price, shop, movie)
118+
self.available = defaultdict(lambda: SortedList())
119+
self.price_map = {}
102120
for shop, movie, price in entries:
103-
self.unrented[movie].add((price, shop))
104-
self.shopAndMovieToPrice[(shop, movie)] = price
121+
self.available[movie].add((price, shop))
122+
self.price_map[self.f(shop, movie)] = price
123+
self.rented = SortedList()
105124

106125
def search(self, movie: int) -> List[int]:
107-
return [shop for _, shop in self.unrented[movie][:5]]
126+
return [shop for _, shop in self.available[movie][:5]]
108127

109128
def rent(self, shop: int, movie: int) -> None:
110-
price = self.shopAndMovieToPrice[(shop, movie)]
111-
self.unrented[movie].remove((price, shop))
129+
price = self.price_map[self.f(shop, movie)]
130+
self.available[movie].remove((price, shop))
112131
self.rented.add((price, shop, movie))
113132

114133
def drop(self, shop: int, movie: int) -> None:
115-
price = self.shopAndMovieToPrice[(shop, movie)]
116-
self.unrented[movie].add((price, shop))
134+
price = self.price_map[self.f(shop, movie)]
117135
self.rented.remove((price, shop, movie))
136+
self.available[movie].add((price, shop))
118137

119138
def report(self) -> List[List[int]]:
120139
return [[shop, movie] for _, shop, movie in self.rented[:5]]
121140

141+
def f(self, shop: int, movie: int) -> int:
142+
return shop << 30 | movie
143+
122144

123145
# Your MovieRentingSystem object will be instantiated and called as such:
124146
# obj = MovieRentingSystem(n, entries)
@@ -128,6 +150,268 @@ class MovieRentingSystem:
128150
# param_4 = obj.report()
129151
```
130152

153+
#### Java
154+
155+
```java
156+
class MovieRentingSystem {
157+
private Map<Integer, TreeSet<int[]>> available = new HashMap<>();
158+
private Map<Long, Integer> priceMap = new HashMap<>();
159+
private TreeSet<int[]> rented = new TreeSet<>((a, b) -> {
160+
if (a[0] != b[0]) {
161+
return a[0] - b[0];
162+
}
163+
if (a[1] != b[1]) {
164+
return a[1] - b[1];
165+
}
166+
return a[2] - b[2];
167+
});
168+
169+
public MovieRentingSystem(int n, int[][] entries) {
170+
for (int[] entry : entries) {
171+
int shop = entry[0], movie = entry[1], price = entry[2];
172+
available
173+
.computeIfAbsent(movie, k -> new TreeSet<>((a, b) -> {
174+
if (a[0] != b[0]) {
175+
return a[0] - b[0];
176+
}
177+
return a[1] - b[1];
178+
}))
179+
.add(new int[] {price, shop});
180+
priceMap.put(f(shop, movie), price);
181+
}
182+
}
183+
184+
public List<Integer> search(int movie) {
185+
List<Integer> res = new ArrayList<>();
186+
if (!available.containsKey(movie)) {
187+
return res;
188+
}
189+
int cnt = 0;
190+
for (int[] item : available.get(movie)) {
191+
res.add(item[1]);
192+
if (++cnt == 5) {
193+
break;
194+
}
195+
}
196+
return res;
197+
}
198+
199+
public void rent(int shop, int movie) {
200+
int price = priceMap.get(f(shop, movie));
201+
available.get(movie).remove(new int[] {price, shop});
202+
rented.add(new int[] {price, shop, movie});
203+
}
204+
205+
public void drop(int shop, int movie) {
206+
int price = priceMap.get(f(shop, movie));
207+
rented.remove(new int[] {price, shop, movie});
208+
available.get(movie).add(new int[] {price, shop});
209+
}
210+
211+
public List<List<Integer>> report() {
212+
List<List<Integer>> res = new ArrayList<>();
213+
int cnt = 0;
214+
for (int[] item : rented) {
215+
res.add(Arrays.asList(item[1], item[2]));
216+
if (++cnt == 5) {
217+
break;
218+
}
219+
}
220+
return res;
221+
}
222+
223+
private long f(int shop, int movie) {
224+
return ((long) shop << 30) | movie;
225+
}
226+
}
227+
228+
/**
229+
* Your MovieRentingSystem object will be instantiated and called as such:
230+
* MovieRentingSystem obj = new MovieRentingSystem(n, entries);
231+
* List<Integer> param_1 = obj.search(movie);
232+
* obj.rent(shop,movie);
233+
* obj.drop(shop,movie);
234+
* List<List<Integer>> param_4 = obj.report();
235+
*/
236+
```
237+
238+
#### C++
239+
240+
```cpp
241+
class MovieRentingSystem {
242+
private:
243+
unordered_map<int, set<pair<int, int>>> available; // movie -> {(price, shop)}
244+
unordered_map<long long, int> priceMap;
245+
set<tuple<int, int, int>> rented; // {(price, shop, movie)}
246+
247+
long long f(int shop, int movie) {
248+
return ((long long) shop << 30) | movie;
249+
}
250+
251+
public:
252+
MovieRentingSystem(int n, vector<vector<int>>& entries) {
253+
for (auto& e : entries) {
254+
int shop = e[0], movie = e[1], price = e[2];
255+
available[movie].insert({price, shop});
256+
priceMap[f(shop, movie)] = price;
257+
}
258+
}
259+
260+
vector<int> search(int movie) {
261+
vector<int> res;
262+
if (!available.count(movie)) {
263+
return res;
264+
}
265+
int cnt = 0;
266+
for (auto& [price, shop] : available[movie]) {
267+
res.push_back(shop);
268+
if (++cnt == 5) {
269+
break;
270+
}
271+
}
272+
return res;
273+
}
274+
275+
void rent(int shop, int movie) {
276+
int price = priceMap[f(shop, movie)];
277+
available[movie].erase({price, shop});
278+
rented.insert({price, shop, movie});
279+
}
280+
281+
void drop(int shop, int movie) {
282+
int price = priceMap[f(shop, movie)];
283+
rented.erase({price, shop, movie});
284+
available[movie].insert({price, shop});
285+
}
286+
287+
vector<vector<int>> report() {
288+
vector<vector<int>> res;
289+
int cnt = 0;
290+
for (auto& [price, shop, movie] : rented) {
291+
res.push_back({shop, movie});
292+
if (++cnt == 5) {
293+
break;
294+
}
295+
}
296+
return res;
297+
}
298+
};
299+
300+
/**
301+
* Your MovieRentingSystem object will be instantiated and called as such:
302+
* MovieRentingSystem* obj = new MovieRentingSystem(n, entries);
303+
* vector<int> param_1 = obj->search(movie);
304+
* obj->rent(shop,movie);
305+
* obj->drop(shop,movie);
306+
* vector<vector<int>> param_4 = obj->report();
307+
*/
308+
```
309+
310+
#### Go
311+
312+
```go
313+
type MovieRentingSystem struct {
314+
available map[int]*treeset.Set // movie -> (price, shop)
315+
priceMap map[int64]int
316+
rented *treeset.Set // (price, shop, movie)
317+
}
318+
319+
func Constructor(n int, entries [][]int) MovieRentingSystem {
320+
// comparator for (price, shop)
321+
cmpAvail := func(a, b any) int {
322+
x := a.([2]int)
323+
y := b.([2]int)
324+
if x[0] != y[0] {
325+
return x[0] - y[0]
326+
}
327+
return x[1] - y[1]
328+
}
329+
// comparator for (price, shop, movie)
330+
cmpRented := func(a, b any) int {
331+
x := a.([3]int)
332+
y := b.([3]int)
333+
if x[0] != y[0] {
334+
return x[0] - y[0]
335+
}
336+
if x[1] != y[1] {
337+
return x[1] - y[1]
338+
}
339+
return x[2] - y[2]
340+
}
341+
342+
mrs := MovieRentingSystem{
343+
available: make(map[int]*treeset.Set),
344+
priceMap: make(map[int64]int),
345+
rented: treeset.NewWith(cmpRented),
346+
}
347+
348+
for _, e := range entries {
349+
shop, movie, price := e[0], e[1], e[2]
350+
if _, ok := mrs.available[movie]; !ok {
351+
mrs.available[movie] = treeset.NewWith(cmpAvail)
352+
}
353+
mrs.available[movie].Add([2]int{price, shop})
354+
mrs.priceMap[f(shop, movie)] = price
355+
}
356+
357+
return mrs
358+
}
359+
360+
func (this *MovieRentingSystem) Search(movie int) []int {
361+
res := []int{}
362+
if _, ok := this.available[movie]; !ok {
363+
return res
364+
}
365+
it := this.available[movie].Iterator()
366+
it.Begin()
367+
cnt := 0
368+
for it.Next() && cnt < 5 {
369+
pair := it.Value().([2]int)
370+
res = append(res, pair[1])
371+
cnt++
372+
}
373+
return res
374+
}
375+
376+
func (this *MovieRentingSystem) Rent(shop int, movie int) {
377+
price := this.priceMap[f(shop, movie)]
378+
this.available[movie].Remove([2]int{price, shop})
379+
this.rented.Add([3]int{price, shop, movie})
380+
}
381+
382+
func (this *MovieRentingSystem) Drop(shop int, movie int) {
383+
price := this.priceMap[f(shop, movie)]
384+
this.rented.Remove([3]int{price, shop, movie})
385+
this.available[movie].Add([2]int{price, shop})
386+
}
387+
388+
func (this *MovieRentingSystem) Report() [][]int {
389+
res := [][]int{}
390+
it := this.rented.Iterator()
391+
it.Begin()
392+
cnt := 0
393+
for it.Next() && cnt < 5 {
394+
t := it.Value().([3]int)
395+
res = append(res, []int{t[1], t[2]})
396+
cnt++
397+
}
398+
return res
399+
}
400+
401+
func f(shop, movie int) int64 {
402+
return (int64(shop) << 30) | int64(movie)
403+
}
404+
405+
/**
406+
* Your MovieRentingSystem object will be instantiated and called as such:
407+
* obj := Constructor(n, entries);
408+
* param_1 := obj.Search(movie);
409+
* obj.Rent(shop,movie);
410+
* obj.Drop(shop,movie);
411+
* param_4 := obj.Report();
412+
*/
413+
```
414+
131415
<!-- tabs:end -->
132416

133417
<!-- solution:end -->

0 commit comments

Comments
 (0)