题目描述:
设计一个支持下述操作的食物评分系统:
- 修改 系统中列出的某种食物的评分。
- 返回系统中某一类烹饪方式下评分最高的食物。
实现 FoodRatings
类:
FoodRatings(String[] foods, String[] cuisines, int[] ratings)
初始化系统。食物由foods
、cuisines
和ratings
描述,长度均为n
。foods[i]
是第i
种食物的名字。cuisines[i]
是第i
种食物的烹饪方式。ratings[i]
是第i
种食物的最初评分。
void changeRating(String food, int newRating)
修改名字为food
的食物的评分。String highestRated(String cuisine)
返回指定烹饪方式cuisine
下评分最高的食物的名字。如果存在并列,返回 字典序较小 的名字。
注意,字符串 x
的字典序比字符串 y
更小的前提是:x
在字典中出现的位置在 y
之前,也就是说,要么 x
是 y
的前缀,或者在满足 x[i] != y[i]
的第一个位置 i
处,x[i]
在字母表中出现的位置在 y[i]
之前。
代码思路:
1. 初始化 (__init__
方法)
- 参数:
foods
: 食物名称的列表。cuisines
: 与食物列表对应的菜系列表。ratings
: 与食物列表对应的评分列表。
- 属性:
self.cuisines
: 使用defaultdict(list)
创建一个字典,键是菜系名称,值是一个列表(实际用作堆)。堆中存储的是元组,元组的第一个元素是评分的相反数(为了使用最大堆的特性),第二个元素是食物名称。self.foods
: 一个字典,键是食物名称,值是一个列表,包含两个元素:菜系名称和评分。
- 实现步骤:
- 遍历
foods
列表,同时获取对应的cuisine
和rating
。 - 将
[-rating, food]
元组添加到对应菜系的堆中(self.cuisines[cuisine]
)。 - 将食物名称、菜系和评分以列表形式存储到
self.foods
字典中。
- 遍历
2. 修改评分 (changeRating
方法)
- 参数:
food
: 需要修改评分的食物名称。newRating
: 新的评分。
- 实现步骤:
- 更新
self.foods
字典中对应食物的评分。 - 获取该食物所属菜系。
- 将新的评分(以
[-newRating, food]
形式)添加到对应菜系的堆中。注意这里没有删除旧的评分,因为堆不支持直接删除元素。不过,由于堆顶始终是当前最高评分的相反数(或更新后的最高评分),所以这种添加方式不会影响查询最高评分的正确性。
- 更新
3. 查询最高评分食物 (highestRated
方法)
- 参数:
cuisine
: 需要查询的菜系名称。
- 返回值:
- 返回该菜系中评分最高的食物名称。
- 实现步骤:
- 获取对应菜系的堆。
- 使用堆的特性,堆顶元素总是评分最高的相反数(因此我们需要取相反数以获取实际评分)。
- 但是,由于可能存在评分更新后堆顶元素未同步更新的情况,我们需要检查堆顶元素的实际评分是否与
self.foods
中存储的评分一致。 - 如果不一致,说明堆顶元素是过期的,使用
heappop
将其弹出,并继续检查下一个堆顶元素,直到找到实际评分与堆顶元素表示的评分一致的食物。 - 返回最高评分的食物名称。
代码实现:
class FoodRatings:
def __init__(self, foods: List[str], cuisines: List[str], ratings: List[int]):
self.cuisines = defaultdict(list) # 按类别建立堆
self.foods = {} # 存每种食物的类别和分数
for i, food in enumerate(foods):
cuisine, rating = cuisines[i], ratings[i]
heappush(self.cuisines[cuisine], [-rating, food])
self.foods[food] = [cuisine, rating]
def changeRating(self, food: str, newRating: int) -> None:
self.foods[food][1] = newRating # 更新分数
cuisine = self.foods[food][0]
# 把更新的分数扔进堆,不需要把旧的找出来删掉
heappush(self.cuisines[cuisine], [-newRating, food])
def highestRated(self, cuisine: str) -> str:
cuisine = self.cuisines[cuisine]
# 堆顶就是最大值
# 但是如果和实际分数不一样说明是过期的信息,弹走
while -cuisine[0][0] != self.foods[cuisine[0][1]][1]:
heappop(cuisine)
return cuisine[0][1]