相对名次

标签: 数组 排序 堆(优先队列)

难度: Easy

给你一个长度为 n 的整数数组 score ,其中 score[i] 是第 i 位运动员在比赛中的得分。所有得分都 互不相同

运动员将根据得分 决定名次 ,其中名次第 1 的运动员得分最高,名次第 2 的运动员得分第 2 高,依此类推。运动员的名次决定了他们的获奖情况:

  • 名次第 1 的运动员获金牌 "Gold Medal"
  • 名次第 2 的运动员获银牌 "Silver Medal"
  • 名次第 3 的运动员获铜牌 "Bronze Medal"
  • 从名次第 4 到第 n 的运动员,只能获得他们的名次编号(即,名次第 x 的运动员获得编号 "x")。

使用长度为 n 的数组 answer 返回获奖,其中 answer[i] 是第 i 位运动员的获奖情况。

示例 1:

输入:score = [5,4,3,2,1]
输出:["Gold Medal","Silver Medal","Bronze Medal","4","5"]
解释:名次为 [1st, 2nd, 3rd, 4th, 5th] 。

示例 2:

输入:score = [10,3,8,9,4]
输出:["Gold Medal","5","Bronze Medal","Silver Medal","4"]
解释:名次为 [1st, 5th, 3rd, 2nd, 4th] 。

提示:

  • n == score.length
  • 1 <= n <= 104
  • 0 <= score[i] <= 106
  • score 中的所有值 互不相同

Submission

运行时间: 31 ms

内存: 17.3 MB

class Solution:
    def findRelativeRanks(self, score: List[int]) -> List[str]:

        ss=sorted(score,reverse=True)
        dic=dict([(j,i+1) for i,j in enumerate(ss)])
        res=[]
        for i in score:
            if dic[i]==1:
                res.append("Gold Medal")
            elif dic[i]==2:
                res.append("Silver Medal")
            elif dic[i]==3:
                res.append("Bronze Medal")
            else:
                res.append(str(dic[i]))
        return res

Explain

该题解首先对输入数组score进行排序,并反转,使得排序后的数组ss按分数从高到低排列。随后,使用列表推导式和enumerate创建一个字典dic,该字典将每个分数映射到其在排序数组中的索引(即名次),由于名次是从1开始的,所以对每个索引加1。然后,对原始score数组中的每个分数查找其名次,根据名次判断赋予相应的奖牌:前三名分别获得'Gold Medal'、'Silver Medal'、'Bronze Medal',其余按名次数字赋值。最后返回结果列表res,该列表包含每个运动员的获奖情况。

时间复杂度: O(n log n)

空间复杂度: O(n)

# 定义一个解决方案类

class Solution:
    def findRelativeRanks(self, score: List[int]) -> List[str]:
        # 对分数列表进行排序并反转,以得到从高到低的顺序
        ss = sorted(score, reverse=True)
        # 通过枚举创建一个映射分数到名次的字典
        dic = dict([(j, i + 1) for i, j in enumerate(ss)])
        # 创建一个空列表用于存放结果
        res = []
        # 遍历原始的分数列表
        for i in score:
            # 根据名次给出相应的奖牌或名次
            if dic[i] == 1:
                res.append("Gold Medal")
            elif dic[i] == 2:
                res.append("Silver Medal")
            elif dic[i] == 3:
                res.append("Bronze Medal")
            else:
                res.append(str(dic[i]))
        # 返回最终的结果列表
        return res

Explore

使用列表推导式和enumerate可以直接在一个表达式内完成映射的构建,这样的方法简洁且易于理解。enumerate提供了一个简便的方式来获取每个元素的索引,这里索引代表了运动员的排名(名次)。直接迭代排序后的数组,我们仍然需要手动处理索引计数,使用enumerate可以自动完成这一工作,代码更为简洁和Pythonic。

为了优化特殊奖牌的处理逻辑,可以定义一个奖牌列表或字典,这样在需要增加或修改奖牌时,只需更新这个列表或字典。例如,可以使用一个字典来映射名次到奖牌的名称,如 {1: 'Gold Medal', 2: 'Silver Medal', 3: 'Bronze Medal'}。这样在代码中,只需查找当前名次在字典中的奖牌,如果不存在,则直接返回名次的字符串形式。这种方法使得管理和扩展奖牌变得灵活和方便。

题解中的方法需要两次遍历是因为第一次遍历用于创建名次字典,第二次用于根据原始分数数组确定每个分数的名次。单次遍历实现相同的结果构建在这种情况下是不可能的,因为我们需要先知道所有分数的全局排序信息来确定名次,这本身就需要至少一次完整的遍历来排序。因此,至少需要两次遍历:一次用于生成排序和名次字典,一次用于按原始顺序分配名次或奖牌。

为了处理空数组的情况,可以在方法开始处添加一个简单的条件检查。如果输入数组`score`是空的,直接返回一个空列表。例如,在`findRelativeRanks`方法的开始,添加`if not score: return []`。这样,当输入为空数组时,方法会立即返回一个空列表,避免后续的逻辑出错。