Skip to content

Commit 4c11b8f

Browse files
committed
+ problem 1912
1 parent 8e68be5 commit 4c11b8f

File tree

5 files changed

+419
-0
lines changed

5 files changed

+419
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# 1912. Design Movie Rental System
2+
You have a movie renting company consisting of `n` shops. You want to implement a renting system that supports searching for, booking, and returning movies. The system should also support generating a report of the currently rented movies.
3+
4+
Each movie is given as a 2D integer array `entries` where <code>entries[i] = [shop<sub>i</sub>, movie<sub>i</sub>, price<sub>i</sub>]</code> indicates that there is a copy of movie <code>movie<sub>i</sub></code> at shop <code>shop<sub>i</sub></code> with a rental price of <code>price<sub>i</sub></code>. Each shop carries **at most one** copy of a movie <code>movie<sub>i</sub></code>.
5+
6+
The system should support the following functions:
7+
8+
* **Search:** Finds the **cheapest 5 shops** that have an **unrented copy** of a given movie. The shops should be sorted by **price** in ascending order, and in case of a tie, the one with the **smaller** <code>shop<sub>i</sub></code> should appear first. If there are less than 5 matching shops, then all of them should be returned. If no shop has an unrented copy, then an empty list should be returned.
9+
* **Rent:** Rents an **unrented copy** of a given movie from a given shop.
10+
* **Drop:** Drops off a **previously rented copy** of a given movie at a given shop.
11+
* **Report:** Returns the **cheapest 5 rented movies** (possibly of the same movie ID) as a 2D list `res` where <code>res[j] = [shop<sub>j</sub>, movie<sub>j</sub>]</code> describes that the <code>j<sup>th</sup></code> cheapest rented movie <code>movie<sub>j</sub></code> was rented from the shop <code>shop<sub>j</sub></code>. The movies in `res` should be sorted by **price** in ascending order, and in case of a tie, the one with the **smaller** <code>shop<sub>j</sub></code> should appear first, and if there is still tie, the one with the **smaller** <code>movie<sub>j</sub></code> should appear first. If there are fewer than 5 rented movies, then all of them should be returned. If no movies are currently being rented, then an empty list should be returned.
12+
13+
Implement the `MovieRentingSystem` class:
14+
15+
* `MovieRentingSystem(int n, int[][] entries)` Initializes the `MovieRentingSystem` object with `n` shops and the movies in `entries`.
16+
* `List<Integer> search(int movie)` Returns a list of shops that have an **unrented copy** of the given `movie` as described above.
17+
* `void rent(int shop, int movie)` Rents the given `movie` from the given `shop`.
18+
* `void drop(int shop, int movie)` Drops off a previously rented `movie` at the given `shop`.
19+
* `List<List<Integer>> report()` Returns a list of cheapest **rented** movies as described above.
20+
21+
**Note:** The test cases will be generated such that `rent` will only be called if the shop has an **unrented** copy of the movie, and `drop` will only be called if the shop had **previously rented** out the movie.
22+
23+
#### Example 1:
24+
<pre>
25+
<strong>Input:</strong>
26+
["MovieRentingSystem", "search", "rent", "rent", "report", "drop", "search"]
27+
[[3, [[0, 1, 5], [0, 2, 6], [0, 3, 7], [1, 1, 4], [1, 2, 7], [2, 1, 5]]], [1], [0, 1], [1, 2], [], [1, 2], [2]]
28+
<strong>Output:</strong>
29+
[null, [1, 0, 2], null, null, [[0, 1], [1, 2]], null, [0, 1]]
30+
<strong>Explanation:</strong>
31+
MovieRentingSystem movieRentingSystem = new MovieRentingSystem(3, [[0, 1, 5], [0, 2, 6], [0, 3, 7], [1, 1, 4], [1, 2, 7], [2, 1, 5]]);
32+
movieRentingSystem.search(1); // return [1, 0, 2], Movies of ID 1 are unrented at shops 1, 0, and 2. Shop 1 is cheapest; shop 0 and 2 are the same price, so order by shop number.
33+
movieRentingSystem.rent(0, 1); // Rent movie 1 from shop 0. Unrented movies at shop 0 are now [2,3].
34+
movieRentingSystem.rent(1, 2); // Rent movie 2 from shop 1. Unrented movies at shop 1 are now [1].
35+
movieRentingSystem.report(); // return [[0, 1], [1, 2]]. Movie 1 from shop 0 is cheapest, followed by movie 2 from shop 1.
36+
movieRentingSystem.drop(1, 2); // Drop off movie 2 at shop 1. Unrented movies at shop 1 are now [1,2].
37+
movieRentingSystem.search(2); // return [0, 1]. Movies of ID 2 are unrented at shops 0 and 1. Shop 0 is cheapest, followed by shop 1.
38+
</pre>
39+
40+
#### Constraints:
41+
* <code>1 <= n <= 3 * 10<sup>5</sup></code>
42+
* <code>1 <= entries.length <= 10<sup>5</sup></code>
43+
* <code>0 <= shop<sub>i</sub> < n</code>
44+
* <code>1 <= movie<sub>i</sub>, price<sub>i</sub> <= 10<sup>4</sup></code>
45+
* Each shop carries **at most one** copy of a movie <code>movie<sub>i</sub></code>.
46+
* At most <code>10<sup>5</sup></code> calls **in total** will be made to `search`, `rent`, `drop` and `report`.
47+
48+
## Solutions (Rust)
49+
50+
### 1. Solution
51+
```Rust
52+
use std::cmp::Reverse;
53+
use std::collections::BinaryHeap;
54+
use std::collections::HashMap;
55+
56+
struct MovieRentingSystem {
57+
rented: HashMap<(i32, i32), (bool, i32)>,
58+
search_heaps: HashMap<i32, BinaryHeap<Reverse<(i32, i32)>>>,
59+
report_heap: BinaryHeap<Reverse<(i32, i32, i32)>>,
60+
}
61+
62+
/**
63+
* `&self` means the method takes an immutable reference.
64+
* If you need a mutable reference, change it to `&mut self` instead.
65+
*/
66+
impl MovieRentingSystem {
67+
fn new(n: i32, entries: Vec<Vec<i32>>) -> Self {
68+
let mut rented = HashMap::new();
69+
let mut search_heaps = HashMap::new();
70+
71+
for i in 0..entries.len() {
72+
let (shop, movie, price) = (entries[i][0], entries[i][1], entries[i][2]);
73+
rented.insert((shop, movie), (false, price));
74+
search_heaps
75+
.entry(movie)
76+
.or_insert(BinaryHeap::new())
77+
.push(Reverse((price, shop)));
78+
}
79+
80+
Self {
81+
rented: rented,
82+
search_heaps: search_heaps,
83+
report_heap: BinaryHeap::new(),
84+
}
85+
}
86+
87+
fn search(&mut self, movie: i32) -> Vec<i32> {
88+
let mut empty = BinaryHeap::new();
89+
let mut heap = self.search_heaps.get_mut(&movie).unwrap_or(&mut empty);
90+
let mut res = vec![];
91+
92+
while let Some(Reverse((price, shop))) = heap.pop() {
93+
if !self.rented[&(shop, movie)].0 && shop != *res.last().unwrap_or(&-1) {
94+
res.push(shop);
95+
}
96+
97+
if res.len() == 5 {
98+
break;
99+
}
100+
}
101+
102+
for &shop in &res {
103+
heap.push(Reverse((self.rented[&(shop, movie)].1, shop)));
104+
}
105+
106+
res
107+
}
108+
109+
fn rent(&mut self, shop: i32, movie: i32) {
110+
self.rented.get_mut(&(shop, movie)).unwrap().0 = true;
111+
self.report_heap
112+
.push(Reverse((self.rented[&(shop, movie)].1, shop, movie)));
113+
}
114+
115+
fn drop(&mut self, shop: i32, movie: i32) {
116+
self.rented.get_mut(&(shop, movie)).unwrap().0 = false;
117+
self.search_heaps
118+
.get_mut(&movie)
119+
.unwrap()
120+
.push(Reverse((self.rented[&(shop, movie)].1, shop)));
121+
}
122+
123+
fn report(&mut self) -> Vec<Vec<i32>> {
124+
let mut res = vec![];
125+
126+
while let Some(Reverse((price, shop, movie))) = self.report_heap.pop() {
127+
if self.rented[&(shop, movie)].0 && &vec![shop, movie] != res.last().unwrap_or(&vec![])
128+
{
129+
res.push(vec![shop, movie]);
130+
}
131+
132+
if res.len() == 5 {
133+
break;
134+
}
135+
}
136+
137+
for i in 0..res.len() {
138+
let (shop, movie) = (res[i][0], res[i][1]);
139+
self.report_heap
140+
.push(Reverse((self.rented[&(shop, movie)].1, shop, movie)));
141+
}
142+
143+
res
144+
}
145+
}
146+
147+
/**
148+
* Your MovieRentingSystem object will be instantiated and called as such:
149+
* let obj = MovieRentingSystem::new(n, entries);
150+
* let ret_1: Vec<i32> = obj.search(movie);
151+
* obj.rent(shop, movie);
152+
* obj.drop(shop, movie);
153+
* let ret_4: Vec<Vec<i32>> = obj.report();
154+
*/
155+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# 1912. 设计电影租借系统
2+
你有一个电影租借公司和 `n` 个电影商店。你想要实现一个电影租借系统,它支持查询、预订和返还电影的操作。同时系统还能生成一份当前被借出电影的报告。
3+
4+
所有电影用二维整数数组 `entries` 表示,其中 <code>entries[i] = [shop<sub>i</sub>, movie<sub>i</sub>, price<sub>i</sub>]</code> 表示商店 <code>shop<sub>i</sub></code> 有一份电影 <code>movie<sub>i</sub></code> 的拷贝,租借价格为 <code>price<sub>i</sub></code> 。每个商店有 **至多一份** 编号为 <code>movie<sub>i</sub></code> 的电影拷贝。
5+
6+
系统需要支持以下操作:
7+
8+
* **Search:**找到拥有指定电影且 **未借出** 的商店中 **最便宜的 5 个** 。商店需要按照 **价格** 升序排序,如果价格相同,则 <code>shop<sub>i</sub></code> **较小** 的商店排在前面。如果查询结果少于 5 个商店,则将它们全部返回。如果查询结果没有任何商店,则返回空列表。
9+
* **Rent:**从指定商店借出指定电影,题目保证指定电影在指定商店 **未借出**
10+
* **Drop:**在指定商店返还 **之前已借出** 的指定电影。
11+
* **Report:**返回 **最便宜的 5 部已借出电影** (可能有重复的电影 ID),将结果用二维列表 `res` 返回,其中 <code>res[j] = [shop<sub>j</sub>, movie<sub>j</sub>]</code> 表示第 `j` 便宜的已借出电影是从商店 <code>shop<sub>j</sub></code> 借出的电影 <code>movie<sub>j</sub></code> 。`res` 中的电影需要按 **价格** 升序排序;如果价格相同,则 <code>shop<sub>j</sub></code> **较小** 的排在前面;如果仍然相同,则 <code>movie<sub>j</sub></code> **较小** 的排在前面。如果当前借出的电影小于 5 部,则将它们全部返回。如果当前没有借出电影,则返回一个空的列表。
12+
13+
请你实现 `MovieRentingSystem` 类:
14+
15+
* `MovieRentingSystem(int n, int[][] entries)``MovieRentingSystem` 对象用 `n` 个商店和 `entries` 表示的电影列表初始化。
16+
* `List<Integer> search(int movie)` 如上所述,返回 **未借出** 指定 `movie` 的商店列表。
17+
* `void rent(int shop, int movie)` 从指定商店 `shop` 借出指定电影 `movie`
18+
* `void drop(int shop, int movie)` 在指定商店 `shop` 返还之前借出的电影 `movie`
19+
* `List<List<Integer>> report()` 如上所述,返回最便宜的 **已借出** 电影列表。
20+
21+
**注意:**测试数据保证 `rent` 操作中指定商店拥有 **未借出** 的指定电影,且 `drop` 操作指定的商店 **之前已借出** 指定电影。
22+
23+
#### 示例 1:
24+
<pre>
25+
<strong>输入:</strong>
26+
["MovieRentingSystem", "search", "rent", "rent", "report", "drop", "search"]
27+
[[3, [[0, 1, 5], [0, 2, 6], [0, 3, 7], [1, 1, 4], [1, 2, 7], [2, 1, 5]]], [1], [0, 1], [1, 2], [], [1, 2], [2]]
28+
<strong>输出:</strong>
29+
[null, [1, 0, 2], null, null, [[0, 1], [1, 2]], null, [0, 1]]
30+
<strong>解释:</strong>
31+
MovieRentingSystem movieRentingSystem = new MovieRentingSystem(3, [[0, 1, 5], [0, 2, 6], [0, 3, 7], [1, 1, 4], [1, 2, 7], [2, 1, 5]]);
32+
movieRentingSystem.search(1); // 返回 [1, 0, 2] ,商店 1,0 和 2 有未借出的 ID 为 1 的电影。商店 1 最便宜,商店 0 和 2 价格相同,所以按商店编号排序。
33+
movieRentingSystem.rent(0, 1); // 从商店 0 借出电影 1 。现在商店 0 未借出电影编号为 [2,3] 。
34+
movieRentingSystem.rent(1, 2); // 从商店 1 借出电影 2 。现在商店 1 未借出的电影编号为 [1] 。
35+
movieRentingSystem.report(); // 返回 [[0, 1], [1, 2]] 。商店 0 借出的电影 1 最便宜,然后是商店 1 借出的电影 2 。
36+
movieRentingSystem.drop(1, 2); // 在商店 1 返还电影 2 。现在商店 1 未借出的电影编号为 [1,2] 。
37+
movieRentingSystem.search(2); // 返回 [0, 1] 。商店 0 和 1 有未借出的 ID 为 2 的电影。商店 0 最便宜,然后是商店 1 。
38+
</pre>
39+
40+
#### 提示:
41+
* <code>1 <= n <= 3 * 10<sup>5</sup></code>
42+
* <code>1 <= entries.length <= 10<sup>5</sup></code>
43+
* <code>0 <= shop<sub>i</sub> < n</code>
44+
* <code>1 <= movie<sub>i</sub>, price<sub>i</sub> <= 10<sup>4</sup></code>
45+
* 每个商店 **至多** 有一份电影 <code>movie<sub>i</sub></code> 的拷贝。
46+
* `search``rent``drop``report` 的调用 **总共** 不超过 <code>10<sup>5</sup></code> 次。
47+
48+
## 题解 (Rust)
49+
50+
### 1. 题解
51+
```Rust
52+
use std::cmp::Reverse;
53+
use std::collections::BinaryHeap;
54+
use std::collections::HashMap;
55+
56+
struct MovieRentingSystem {
57+
rented: HashMap<(i32, i32), (bool, i32)>,
58+
search_heaps: HashMap<i32, BinaryHeap<Reverse<(i32, i32)>>>,
59+
report_heap: BinaryHeap<Reverse<(i32, i32, i32)>>,
60+
}
61+
62+
/**
63+
* `&self` means the method takes an immutable reference.
64+
* If you need a mutable reference, change it to `&mut self` instead.
65+
*/
66+
impl MovieRentingSystem {
67+
fn new(n: i32, entries: Vec<Vec<i32>>) -> Self {
68+
let mut rented = HashMap::new();
69+
let mut search_heaps = HashMap::new();
70+
71+
for i in 0..entries.len() {
72+
let (shop, movie, price) = (entries[i][0], entries[i][1], entries[i][2]);
73+
rented.insert((shop, movie), (false, price));
74+
search_heaps
75+
.entry(movie)
76+
.or_insert(BinaryHeap::new())
77+
.push(Reverse((price, shop)));
78+
}
79+
80+
Self {
81+
rented: rented,
82+
search_heaps: search_heaps,
83+
report_heap: BinaryHeap::new(),
84+
}
85+
}
86+
87+
fn search(&mut self, movie: i32) -> Vec<i32> {
88+
let mut empty = BinaryHeap::new();
89+
let mut heap = self.search_heaps.get_mut(&movie).unwrap_or(&mut empty);
90+
let mut res = vec![];
91+
92+
while let Some(Reverse((price, shop))) = heap.pop() {
93+
if !self.rented[&(shop, movie)].0 && shop != *res.last().unwrap_or(&-1) {
94+
res.push(shop);
95+
}
96+
97+
if res.len() == 5 {
98+
break;
99+
}
100+
}
101+
102+
for &shop in &res {
103+
heap.push(Reverse((self.rented[&(shop, movie)].1, shop)));
104+
}
105+
106+
res
107+
}
108+
109+
fn rent(&mut self, shop: i32, movie: i32) {
110+
self.rented.get_mut(&(shop, movie)).unwrap().0 = true;
111+
self.report_heap
112+
.push(Reverse((self.rented[&(shop, movie)].1, shop, movie)));
113+
}
114+
115+
fn drop(&mut self, shop: i32, movie: i32) {
116+
self.rented.get_mut(&(shop, movie)).unwrap().0 = false;
117+
self.search_heaps
118+
.get_mut(&movie)
119+
.unwrap()
120+
.push(Reverse((self.rented[&(shop, movie)].1, shop)));
121+
}
122+
123+
fn report(&mut self) -> Vec<Vec<i32>> {
124+
let mut res = vec![];
125+
126+
while let Some(Reverse((price, shop, movie))) = self.report_heap.pop() {
127+
if self.rented[&(shop, movie)].0 && &vec![shop, movie] != res.last().unwrap_or(&vec![])
128+
{
129+
res.push(vec![shop, movie]);
130+
}
131+
132+
if res.len() == 5 {
133+
break;
134+
}
135+
}
136+
137+
for i in 0..res.len() {
138+
let (shop, movie) = (res[i][0], res[i][1]);
139+
self.report_heap
140+
.push(Reverse((self.rented[&(shop, movie)].1, shop, movie)));
141+
}
142+
143+
res
144+
}
145+
}
146+
147+
/**
148+
* Your MovieRentingSystem object will be instantiated and called as such:
149+
* let obj = MovieRentingSystem::new(n, entries);
150+
* let ret_1: Vec<i32> = obj.search(movie);
151+
* obj.rent(shop, movie);
152+
* obj.drop(shop, movie);
153+
* let ret_4: Vec<Vec<i32>> = obj.report();
154+
*/
155+
```

0 commit comments

Comments
 (0)