Skip to content

Commit 8f4f80c

Browse files
authored
Merge pull request #1320 from 0xff-dev/1912
Add solution and test-cases for problem 1912
2 parents b888a4f + fb159f5 commit 8f4f80c

File tree

3 files changed

+233
-28
lines changed

3 files changed

+233
-28
lines changed

leetcode/1901-2000/1912.Design-Movie-Rental-System/README.md

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,45 @@
11
# [1912.Design Movie Rental System][title]
22

3-
> [!WARNING|style:flat]
4-
> This question is temporarily unanswered if you have good ideas. Welcome to [Create Pull Request PR](https://github.com/kylesliu/awesome-golang-algorithm)
5-
63
## Description
4+
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.
75

8-
**Example 1:**
6+
Each movie is given as a 2D integer array `entries` where `entries[i] = [shopi, moviei, pricei]` indicates that there is a copy of movie `moviei` at shop `shopi` with a rental price of `pricei`. Each shop carries **at most one** copy of a movie `moviei`.
97

10-
```
11-
Input: a = "11", b = "1"
12-
Output: "100"
13-
```
8+
The system should support the following functions:
149

15-
## 题意
16-
> ...
10+
- **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** `shopi` 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.
11+
- **Rent**: Rents an **unrented copy** of a given movie from a given shop.
12+
- **Drop**: Drops off a **previously rented copy** of a given movie at a given shop.
13+
- **Report**: Returns the **cheapest 5 rented movies** (possibly of the same movie ID) as a 2D list `res` where `res[j] = [shopj, moviej]` describes that the `jth` cheapest rented movie `moviei` was rented from the shop `shopj`. The movies in `res` should be sorted by **price** in ascending order, and in case of a tie, the one with the **smaller** shopj should appear first, and if there is still tie, the one with the **smaller** `moviej` 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.
1714

18-
## 题解
15+
Implement the `MovieRentingSystem` class:
1916

20-
### 思路1
21-
> ...
22-
Design Movie Rental System
23-
```go
24-
```
17+
- `MovieRentingSystem(int n, int[][] entries)` Initializes the `MovieRentingSystem` object with `n` shops and the movies in `entries`.
18+
- `List<Integer> search(int movie)` Returns a list of shops that have an **unrented copy** of the given `movie` as described above.
19+
- `void rent(int shop, int movie)` Rents the given `movie` from the given `shop`.
20+
- `void drop(int shop, int movie)` Drops off a previously rented `movie` at the given `shop`.
21+
- `List<List<Integer>> report()` Returns a list of cheapest **rented** movies as described above.
2522

23+
**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.
24+
25+
**Example 1:**
26+
27+
```
28+
Input
29+
["MovieRentingSystem", "search", "rent", "rent", "report", "drop", "search"]
30+
[[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]]
31+
Output
32+
[null, [1, 0, 2], null, null, [[0, 1], [1, 2]], null, [0, 1]]
33+
34+
Explanation
35+
MovieRentingSystem movieRentingSystem = new MovieRentingSystem(3, [[0, 1, 5], [0, 2, 6], [0, 3, 7], [1, 1, 4], [1, 2, 7], [2, 1, 5]]);
36+
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.
37+
movieRentingSystem.rent(0, 1); // Rent movie 1 from shop 0. Unrented movies at shop 0 are now [2,3].
38+
movieRentingSystem.rent(1, 2); // Rent movie 2 from shop 1. Unrented movies at shop 1 are now [1].
39+
movieRentingSystem.report(); // return [[0, 1], [1, 2]]. Movie 1 from shop 0 is cheapest, followed by movie 2 from shop 1.
40+
movieRentingSystem.drop(1, 2); // Drop off movie 2 at shop 1. Unrented movies at shop 1 are now [1,2].
41+
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.
42+
```
2643

2744
## 结语
2845

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,184 @@
11
package Solution
22

3-
func Solution(x bool) bool {
3+
import (
4+
"container/heap"
5+
"sort"
6+
)
7+
8+
type movie struct {
9+
shop, movie, price, index int
10+
}
11+
12+
type movieList []*movie
13+
14+
func (m *movieList) Len() int {
15+
return len(*m)
16+
}
17+
func (m *movieList) Swap(i, j int) {
18+
(*m)[i], (*m)[j] = (*m)[j], (*m)[i]
19+
(*m)[i].index = i
20+
(*m)[j].index = j
21+
}
22+
23+
func (m *movieList) Less(i, j int) bool {
24+
a, b := (*m)[i], (*m)[j]
25+
if a.price != b.price {
26+
return a.price < b.price
27+
}
28+
if a.shop != b.shop {
29+
return a.shop < b.shop
30+
}
31+
return a.movie < b.movie
32+
}
33+
34+
func (m *movieList) Push(x any) {
35+
mv := x.(*movie)
36+
l := len(*m)
37+
mv.index = l
38+
*m = append(*m, mv)
39+
}
40+
41+
func (m *movieList) Pop() any {
42+
old := *m
43+
l := len(old)
44+
x := old[l-1]
45+
*m = old[:l-1]
446
return x
547
}
48+
49+
type MovieRentingSystem struct {
50+
// 每个电影自己的
51+
movieShops map[int]*movieList
52+
// 已经租界的电影列表
53+
rentQueue *movieList
54+
index map[[2]int]*movie
55+
56+
n int
57+
}
58+
59+
func Constructor(n int, entries [][]int) MovieRentingSystem {
60+
instance := MovieRentingSystem{
61+
movieShops: make(map[int]*movieList),
62+
rentQueue: &movieList{},
63+
index: make(map[[2]int]*movie),
64+
n: n,
65+
}
66+
// shop, movie, price
67+
// movie, shop
68+
for _, ent := range entries {
69+
// shop, movie
70+
key := [2]int{ent[0], ent[1]}
71+
if _, ok := instance.movieShops[ent[1]]; !ok {
72+
instance.movieShops[ent[1]] = &movieList{}
73+
}
74+
m := &movie{shop: ent[0], movie: ent[1], price: ent[2], index: 0}
75+
instance.index[key] = m
76+
heap.Push(instance.movieShops[ent[1]], m)
77+
}
78+
return instance
79+
}
80+
81+
func (this *MovieRentingSystem) Search(m int) []int {
82+
top5 := [][]int{}
83+
list := this.movieShops[m]
84+
if list == nil {
85+
return nil
86+
}
87+
store := make([]*movie, 5)
88+
index := 0
89+
for list.Len() > 0 && index < 5 {
90+
top := heap.Pop(list).(*movie)
91+
store[index] = top
92+
index++
93+
top5 = append(top5, []int{top.shop, top.price})
94+
}
95+
for i := 0; i < index; i++ {
96+
heap.Push(list, store[i])
97+
}
98+
sort.Slice(top5, func(i, j int) bool {
99+
a, b := top5[i], top5[j]
100+
if a[1] != b[1] {
101+
return a[1] < b[1]
102+
}
103+
return a[0] < b[0]
104+
})
105+
ret := make([]int, len(top5))
106+
for i := range top5 {
107+
ret[i] = top5[i][0]
108+
}
109+
110+
return ret
111+
}
112+
113+
func (this *MovieRentingSystem) Rent(shop int, m int) {
114+
// 需要记录价格
115+
key := [2]int{shop, m}
116+
item := this.index[key]
117+
_ = heap.Remove(this.movieShops[m], item.index)
118+
heap.Push(this.rentQueue, item)
119+
}
120+
121+
func (this *MovieRentingSystem) Drop(shop int, m int) {
122+
key := [2]int{shop, m}
123+
item := this.index[key]
124+
heap.Remove(this.rentQueue, item.index)
125+
heap.Push(this.movieShops[m], item)
126+
}
127+
128+
func (this *MovieRentingSystem) Report() [][]int {
129+
top5 := [][]int{}
130+
store := make([]*movie, 5)
131+
index := 0
132+
for this.rentQueue.Len() > 0 && index < 5 {
133+
top := heap.Pop(this.rentQueue).(*movie)
134+
store[index] = top
135+
index++
136+
top5 = append(top5, []int{top.shop, top.movie, top.price})
137+
}
138+
for i := 0; i < index; i++ {
139+
heap.Push(this.rentQueue, store[i])
140+
}
141+
142+
sort.Slice(top5, func(i, j int) bool {
143+
a, b := top5[i], top5[j]
144+
if a[2] != b[2] {
145+
return a[2] < b[2]
146+
}
147+
if a[0] != b[0] {
148+
return a[0] < b[0]
149+
}
150+
return a[1] < b[1]
151+
})
152+
ret := make([][]int, len(top5))
153+
for i := range top5 {
154+
ret[i] = top5[i][:2]
155+
}
156+
157+
return ret
158+
}
159+
160+
type op struct {
161+
name string
162+
shop, movie int
163+
}
164+
165+
func Solution(m int, entries [][]int, ops []op) []any {
166+
c := Constructor(m, entries)
167+
ret := make([]any, 0)
168+
for _, o := range ops {
169+
if o.name == "rent" {
170+
c.Rent(o.shop, o.movie)
171+
continue
172+
}
173+
if o.name == "drop" {
174+
c.Drop(o.shop, o.movie)
175+
continue
176+
}
177+
if o.name == "search" {
178+
ret = append(ret, c.Search(o.movie))
179+
continue
180+
}
181+
ret = append(ret, c.Report())
182+
}
183+
return ret
184+
}

leetcode/1901-2000/1912.Design-Movie-Rental-System/Solution_test.go

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,40 @@ import (
99
func TestSolution(t *testing.T) {
1010
// 测试用例
1111
cases := []struct {
12-
name string
13-
inputs bool
14-
expect bool
12+
name string
13+
m int
14+
entries [][]int
15+
ops []op
16+
expect []any
1517
}{
16-
{"TestCase", true, true},
17-
{"TestCase", true, true},
18-
{"TestCase", false, false},
18+
{"TestCase1", 3, [][]int{
19+
{0, 1, 5}, {0, 2, 6}, {0, 3, 7}, {1, 1, 4}, {1, 2, 7}, {2, 1, 5},
20+
}, []op{
21+
{name: "search", movie: 1},
22+
{name: "rent", shop: 0, movie: 1},
23+
{name: "rent", shop: 1, movie: 2},
24+
{name: "report"},
25+
{name: "drop", shop: 1, movie: 2},
26+
{name: "search", movie: 2},
27+
}, []any{[]int{1, 0, 2}, [][]int{{0, 1}, {1, 2}}, []int{0, 1}}},
1928
}
2029

2130
// 开始测试
2231
for i, c := range cases {
2332
t.Run(c.name+" "+strconv.Itoa(i), func(t *testing.T) {
24-
got := Solution(c.inputs)
33+
got := Solution(c.m, c.entries, c.ops)
2534
if !reflect.DeepEqual(got, c.expect) {
26-
t.Fatalf("expected: %v, but got: %v, with inputs: %v",
27-
c.expect, got, c.inputs)
35+
t.Fatalf("expected: %v, but got: %v, with inputs: %v %v %v",
36+
c.expect, got, c.m, c.entries, c.ops)
2837
}
2938
})
3039
}
3140
}
3241

33-
// 压力测试
42+
// 压力测试
3443
func BenchmarkSolution(b *testing.B) {
3544
}
3645

37-
// 使用案列
46+
// 使用案列
3847
func ExampleSolution() {
3948
}

0 commit comments

Comments
 (0)