Skip to content

Commit 65cbd25

Browse files
authored
feat: add solutions to lc problem: No.2353 (#4114)
No.2353.Design a Food Rating System
1 parent 584991e commit 65cbd25

File tree

6 files changed

+400
-84
lines changed

6 files changed

+400
-84
lines changed

solution/2300-2399/2353.Design a Food Rating System/README.md

+141-28
Original file line numberDiff line numberDiff line change
@@ -95,30 +95,42 @@ foodRatings.highestRated("japanese"); // 返回 "ramen"
9595

9696
<!-- solution:start -->
9797

98-
### 方法一
98+
### 方法一:哈希表 + 有序集合
99+
100+
我们可以使用哈希表 $\textit{d}$ 来存储每种烹饪方式下的食物,其中键是烹饪方式,值是一个有序集合,有序集合的每个元素是一个二元组 $(\textit{rating}, \textit{food})$,按照评分从高到低排序,如果评分相同,则按照食物名字的字典序从小到大排序。
101+
102+
我们还可以使用哈希表 $\textit{g}$ 来存储每种食物的评分和烹饪方式。即 $\textit{g}[\textit{food}] = (\textit{rating}, \textit{cuisine})$。
103+
104+
在构造函数中,我们遍历 $\textit{foods}$、$\textit{cuisines}$ 和 $\textit{ratings}$,将每种食物的评分和烹饪方式存储到 $\textit{d}$ 和 $\textit{g}$ 中。
105+
106+
在 $\textit{changeRating}$ 函数中,我们首先获取食物 $\textit{food}$ 的原评分 $\textit{oldRating}$ 和烹饪方式 $\textit{cuisine}$,然后更新 $\textit{g}[\textit{food}]$ 的评分为 $\textit{newRating}$,并从 $\textit{d}[\textit{cuisine}]$ 中删除 $(\textit{oldRating}, \textit{food})$,并将 $(\textit{newRating}, \textit{food})$ 添加到 $\textit{d}[\textit{cuisine}]$ 中。
107+
108+
在 $\textit{highestRated}$ 函数中,我们直接返回 $\textit{d}[\textit{cuisine}]$ 的第一个元素的食物名字即可。
109+
110+
时间复杂度方面,构造函数的时间复杂度为 $O(n \log n)$,其中 $n$ 是食物的数量。其余操作的时间复杂度为 $O(\log n)$。空间复杂度为 $O(n)$。
99111

100112
<!-- tabs:start -->
101113

102114
#### Python3
103115

104116
```python
105117
class FoodRatings:
106-
def __init__(self, foods: List[str], cuisines: List[str], ratings: List[int]):
107-
self.mp = {}
108-
self.t = defaultdict(lambda: SortedSet(key=lambda x: (-x[0], x[1])))
109118

110-
for a, b, c in zip(foods, cuisines, ratings):
111-
self.mp[a] = (b, c)
112-
self.t[b].add((c, a))
119+
def __init__(self, foods: List[str], cuisines: List[str], ratings: List[int]):
120+
self.d = defaultdict(SortedList)
121+
self.g = {}
122+
for food, cuisine, rating in zip(foods, cuisines, ratings):
123+
self.d[cuisine].add((-rating, food))
124+
self.g[food] = (rating, cuisine)
113125

114126
def changeRating(self, food: str, newRating: int) -> None:
115-
b, c = self.mp[food]
116-
self.mp[food] = (b, newRating)
117-
self.t[b].remove((c, food))
118-
self.t[b].add((newRating, food))
127+
oldRating, cuisine = self.g[food]
128+
self.g[food] = (newRating, cuisine)
129+
self.d[cuisine].remove((-oldRating, food))
130+
self.d[cuisine].add((-newRating, food))
119131

120132
def highestRated(self, cuisine: str) -> str:
121-
return self.t[cuisine][0][1]
133+
return self.d[cuisine][0][1]
122134

123135

124136
# Your FoodRatings object will be instantiated and called as such:
@@ -127,36 +139,78 @@ class FoodRatings:
127139
# param_2 = obj.highestRated(cuisine)
128140
```
129141

142+
#### Java
143+
144+
```java
145+
class FoodRatings {
146+
private Map<String, TreeSet<Pair<Integer, String>>> d = new HashMap<>();
147+
private Map<String, Pair<Integer, String>> g = new HashMap<>();
148+
private final Comparator<Pair<Integer, String>> cmp = (a, b) -> {
149+
if (!a.getKey().equals(b.getKey())) {
150+
return b.getKey().compareTo(a.getKey());
151+
}
152+
return a.getValue().compareTo(b.getValue());
153+
};
154+
155+
public FoodRatings(String[] foods, String[] cuisines, int[] ratings) {
156+
for (int i = 0; i < foods.length; ++i) {
157+
String food = foods[i], cuisine = cuisines[i];
158+
int rating = ratings[i];
159+
d.computeIfAbsent(cuisine, k -> new TreeSet<>(cmp)).add(new Pair<>(rating, food));
160+
g.put(food, new Pair<>(rating, cuisine));
161+
}
162+
}
163+
164+
public void changeRating(String food, int newRating) {
165+
Pair<Integer, String> old = g.get(food);
166+
int oldRating = old.getKey();
167+
String cuisine = old.getValue();
168+
g.put(food, new Pair<>(newRating, cuisine));
169+
d.get(cuisine).remove(new Pair<>(oldRating, food));
170+
d.get(cuisine).add(new Pair<>(newRating, food));
171+
}
172+
173+
public String highestRated(String cuisine) {
174+
return d.get(cuisine).first().getValue();
175+
}
176+
}
177+
178+
/**
179+
* Your FoodRatings object will be instantiated and called as such:
180+
* FoodRatings obj = new FoodRatings(foods, cuisines, ratings);
181+
* obj.changeRating(food,newRating);
182+
* String param_2 = obj.highestRated(cuisine);
183+
*/
184+
```
185+
130186
#### C++
131187

132188
```cpp
133-
using pis = pair<int, string>;
134-
135189
class FoodRatings {
136-
map<string, pis> mp;
137-
map<string, set<pis>> t;
138-
139190
public:
140191
FoodRatings(vector<string>& foods, vector<string>& cuisines, vector<int>& ratings) {
141-
int n = foods.size();
142-
for (int i = 0; i < n; ++i) {
143-
string a = foods[i], b = cuisines[i];
144-
int c = ratings[i];
145-
mp[a] = pis(c, b);
146-
t[b].insert(pis(-c, a));
192+
for (int i = 0; i < foods.size(); ++i) {
193+
string food = foods[i], cuisine = cuisines[i];
194+
int rating = ratings[i];
195+
d[cuisine].insert({-rating, food});
196+
g[food] = {rating, cuisine};
147197
}
148198
}
149199

150200
void changeRating(string food, int newRating) {
151-
pis& p = mp[food];
152-
t[p.second].erase(pis(-p.first, food));
153-
p.first = newRating;
154-
t[p.second].insert(pis(-p.first, food));
201+
auto [oldRating, cuisine] = g[food];
202+
g[food] = {newRating, cuisine};
203+
d[cuisine].erase({-oldRating, food});
204+
d[cuisine].insert({-newRating, food});
155205
}
156206

157207
string highestRated(string cuisine) {
158-
return t[cuisine].begin()->second;
208+
return d[cuisine].begin()->second;
159209
}
210+
211+
private:
212+
unordered_map<string, set<pair<int, string>>> d;
213+
unordered_map<string, pair<int, string>> g;
160214
};
161215

162216
/**
@@ -167,6 +221,65 @@ public:
167221
*/
168222
```
169223
224+
#### Go
225+
226+
```go
227+
import (
228+
"github.com/emirpasic/gods/v2/trees/redblacktree"
229+
)
230+
231+
type pair struct {
232+
rating int
233+
food string
234+
}
235+
236+
type FoodRatings struct {
237+
d map[string]*redblacktree.Tree[pair, struct{}]
238+
g map[string]pair
239+
}
240+
241+
func Constructor(foods []string, cuisines []string, ratings []int) FoodRatings {
242+
d := make(map[string]*redblacktree.Tree[pair, struct{}])
243+
g := make(map[string]pair)
244+
245+
for i, food := range foods {
246+
rating, cuisine := ratings[i], cuisines[i]
247+
g[food] = pair{rating, cuisine}
248+
249+
if d[cuisine] == nil {
250+
d[cuisine] = redblacktree.NewWith[pair, struct{}](func(a, b pair) int {
251+
return cmp.Or(b.rating-a.rating, strings.Compare(a.food, b.food))
252+
})
253+
}
254+
d[cuisine].Put(pair{rating, food}, struct{}{})
255+
}
256+
257+
return FoodRatings{d, g}
258+
}
259+
260+
func (this *FoodRatings) ChangeRating(food string, newRating int) {
261+
p := this.g[food]
262+
t := this.d[p.food]
263+
264+
t.Remove(pair{p.rating, food})
265+
t.Put(pair{newRating, food}, struct{}{})
266+
267+
p.rating = newRating
268+
this.g[food] = p
269+
}
270+
271+
func (this *FoodRatings) HighestRated(cuisine string) string {
272+
return this.d[cuisine].Left().Key.food
273+
}
274+
275+
/**
276+
* Your FoodRatings object will be instantiated and called as such:
277+
* obj := Constructor(foods, cuisines, ratings);
278+
* obj.ChangeRating(food,newRating);
279+
* param_2 := obj.HighestRated(cuisine);
280+
*/
281+
```
282+
170283
<!-- tabs:end -->
171284

172285
<!-- solution:end -->

0 commit comments

Comments
 (0)