@@ -87,38 +87,60 @@ movieRentingSystem.search(2); // 返回 [0, 1] 。商店 0 和 1 有未借出
87
87
88
88
<!-- solution:start -->
89
89
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}$ 的长度。
91
109
92
110
<!-- tabs:start -->
93
111
94
112
#### Python3
95
113
96
114
``` python
97
115
class MovieRentingSystem :
116
+
98
117
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 = {}
102
120
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()
105
124
106
125
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 ]]
108
127
109
128
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))
112
131
self .rented.add((price, shop, movie))
113
132
114
133
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)]
117
135
self .rented.remove((price, shop, movie))
136
+ self .available[movie].add((price, shop))
118
137
119
138
def report (self ) -> List[List[int ]]:
120
139
return [[shop, movie] for _, shop, movie in self .rented[:5 ]]
121
140
141
+ def f (self , shop : int , movie : int ) -> int :
142
+ return shop << 30 | movie
143
+
122
144
123
145
# Your MovieRentingSystem object will be instantiated and called as such:
124
146
# obj = MovieRentingSystem(n, entries)
@@ -128,6 +150,268 @@ class MovieRentingSystem:
128
150
# param_4 = obj.report()
129
151
```
130
152
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
+
131
415
<!-- tabs:end -->
132
416
133
417
<!-- solution:end -->
0 commit comments