游戏排名三大的分数|豆包MarsCode AI刷题

56 阅读11分钟

问题描述 小M想要通过查看往届游戏比赛的排名来确定自己比赛的目标分数。他希望找到往届比赛中排名第三的分数,作为自己的目标。具体规则如下: 如果分数中有三个或以上不同的分数,返回其中第三大的分数。 如果不同的分数只有两个或更少,那么小M将选择最大的分数作为他的目标。 请你帮小M根据给定的分数数组计算目标分数。 为了帮助小M确定他的目标分数,我们需要编写一个函数来解析给定的分数数组,并根据规则返回相应的分数。以下是实现这个功能的Python代码:

python复制代码
	def find_target_score(scores):

	    # 去除重复分数,并排序

	    unique_scores = sorted(set(scores), reverse=True)

	    

	    # 根据规则返回目标分数

	    if len(unique_scores) >= 3:

	        return unique_scores[2]  # 返回第三大的分数

	    else:

	        return unique_scores[0]  # 返回最大的分数

	 

	# 示例用法

	scores = [100, 90, 80, 90, 70, 100, 60]

	target_score = find_target_score(scores)

	print(f"目标分数是: {target_score}")

代码解析

  1. 去除重复分数

    • 使用 set(scores) 将分数数组转换为集合,以去除重复项。
    • 使用 sorted(..., reverse=True) 对去重后的分数进行降序排序。
  2. 根据规则返回目标分数

    • 如果 unique_scores 的长度(即不同分数的数量)大于等于3,则返回排序后的第三个分数(索引为2,因为索引从0开始)。
    • 否则,返回排序后的第一个分数(即最大的分数)。

示例

假设输入分数数组为 [100, 90, 80, 90, 70, 100, 60]

  • 去重并排序后得到 [100, 90, 80, 70, 60]
  • 因为有5个不同的分数,所以返回第三大的分数 80

如果输入分数数组为 [100, 90, 90, 100]

  • 去重并排序后得到 [100, 90]
  • 因为只有2个不同的分数,所以返回最大的分数 100

总结

通过这个函数,小M可以很方便地根据往届比赛的分数来确定自己的目标分数。这个函数处理了分数重复的情况,并根据规则返回了合适的分数。当然,为了让解释更加详细和具体,我们可以逐步分析代码中的每个部分,并给出更多的背景信息和示例。以下是更详细的解析:

问题背景

小M想要通过查看往届游戏比赛的排名来确定自己比赛的目标分数。他特别关注排名第三的分数,但有一个条件:如果不同的分数少于三个,他就选择最高的分数作为目标。

解决方案

为了解决这个问题,我们需要编写一个函数,该函数接受一个分数数组作为输入,并返回目标分数。目标分数的确定基于以下规则:

  1. 如果数组中有三个或更多不同的分数,则返回第三大的分数。
  2. 如果数组中的不同分数少于三个,则返回最大的分数。

代码实现

以下是Python代码的实现,并附有详细的注释:

python复制代码
	def find_target_score(scores):

	    """

	    根据给定的分数数组,返回目标分数。

	    

	    参数:

	    scores (list of int): 分数数组,包含多个比赛的分数。

	    

	    返回:

	    int: 目标分数,根据规则确定。

	    """

	    

	    # 第一步:去除重复分数

	    # 使用set数据结构来去除数组中的重复元素,因为set不允许重复元素。

	    unique_scores = set(scores)

	    

	    # 第二步:对分数进行排序

	    # 由于我们需要找到第三大的分数(如果可能),因此需要对分数进行降序排序。

	    # sorted函数返回一个新的列表,并且我们可以使用reverse=True参数来进行降序排序。

	    sorted_unique_scores = sorted(unique_scores, reverse=True)

	    

	    # 第三步:根据规则返回目标分数

	    # 检查排序后的分数列表的长度。

	    if len(sorted_unique_scores) >= 3:

	        # 如果列表中有三个或更多不同的分数,则返回第三大的分数(索引为2)。

	        target_score = sorted_unique_scores[2]

	    else:

	        # 如果列表中的不同分数少于三个,则返回最大的分数(索引为0)。

	        target_score = sorted_unique_scores[0]

	    

	    # 返回目标分数

	    return target_score

	 

	# 示例用法

	# 假设有以下分数数组,代表往届比赛的分数

	scores = [100, 90, 80, 90, 70, 100, 60]

	# 调用函数并打印结果

	target_score = find_target_score(scores)

	print(f"根据规则,目标分数是: {target_score}")

代码运行示例

对于上面的示例分数数组 [100, 90, 80, 90, 70, 100, 60]

  1. 去除重复分数后得到 {60, 70, 80, 90, 100}
  2. 对分数进行降序排序后得到 [100, 90, 80, 70, 60]
  3. 因为有5个不同的分数,所以返回第三大的分数 80

如果分数数组为 [100, 90, 90, 100]

  1. 去除重复分数后得到 {90, 100}
  2. 对分数进行降序排序后得到 [100, 90]
  3. 因为只有2个不同的分数,所以返回最大的分数 100

总结

通过这个函数,小M可以轻松地根据往届比赛的分数来确定自己的目标分数。函数首先去除重复分数,然后对分数进行排序,最后根据规则返回合适的分数。 当然,除了之前提到的使用set去重和sorted排序的解决方案外,还有其他几种方法可以实现相同的功能。以下是其中两种可能的解决方案:

解决方案 1:使用计数字典和排序

这种方法使用字典来计数每个分数的出现次数,然后根据分数进行排序。这种方法的好处是它可以同时处理去重和排序,而且可以在排序时保留原始分数的出现次数(如果需要的话)。不过在这个特定问题中,我们不需要保留出现次数,所以只需要排序即可。

python复制代码
	def find_target_score(scores):

	    # 使用字典来计数每个分数的出现次数

	    score_count = {}

	    for score in scores:

	        if score in score_count:

	            score_count[score] += 1

	        else:

	            score_count[score] = 1

	    

	    # 将分数和它们的计数转换为元组列表,并排序

	    # 这里我们只关心分数,所以排序后只需要分数部分

	    sorted_scores = sorted((score, count) for score, count in score_count.items(), reverse=True)

	    

	    # 根据规则返回目标分数

	    if len(sorted_scores) >= 3:

	        target_score = sorted_scores[2][0]  # 返回第三大的分数

	    else:

	        target_score = sorted_scores[0][0]  # 返回最大的分数

	    

	    return target_score

	 

	# 示例用法

	scores = [100, 90, 80, 90, 70, 100, 60]

	target_score = find_target_score(scores)

	print(f"目标分数是: {target_score}")

解决方案 2:使用堆(优先队列)

这种方法使用Python的heapq模块来维护一个最小堆(或最大堆的负数表示),以便在遍历分数时动态地找到第三大的分数。这种方法在处理大量数据时可能更高效,因为它不需要对整个数据集进行排序。

然而,对于这个问题来说,由于我们只需要找到第三大的分数(或最大的分数,如果不同的分数少于三个),我们可以使用一个大小为3的最小堆来存储当前遇到的最大的三个分数(如果分数少于三个,则堆的大小会小于3)。在遍历完所有分数后,堆顶元素将是第三大的分数(如果堆的大小为3),否则堆顶元素将是最大的分数。

但需要注意的是,由于Python的heapq默认是最小堆,我们需要存储分数的负数来模拟最大堆的行为,或者在比较时反转比较逻辑。

以下是一个使用最小堆(通过存储负数来模拟最大堆)的示例:

python复制代码
	import heapq

	 

	def find_target_score(scores):

	    # 使用一个大小为3的最小堆来存储当前最大的三个分数(存储为负数)

	    max_heap = []

	    for score in scores:

	        # 由于heapq是最小堆,我们存储负数以模拟最大堆

	        heapq.heappush(max_heap, -score)

	        # 如果堆的大小超过3,则弹出最小的元素(即当前三个最大分数中最小的那个的负数)

	        if len(max_heap) > 3:

	            heapq.heappop(max_heap)

	    

	    # 堆顶元素是当前三个最大分数中最小的那个的负数,所以我们需要取反来得到实际的分数

	    # 如果堆的大小小于3,则堆顶元素将是最大的分数(仍然需要取反)

	    target_score = -max_heap[0] if max_heap else float('-inf')  # 如果没有分数,则返回一个不可能的低分

	    # 但是由于我们总是至少会推送一个分数到堆中(即使它重复),所以上面的else分支实际上不会执行

	    # 更安全的做法是检查堆的大小,并相应地返回最大的分数或第三大的分数

	    if len(max_heap) == 3:

	        # 如果堆中有三个元素,则返回第三大的分数(堆顶元素取反后)

	        target_score = -max_heap[2]  # 注意这里取的是索引2,因为堆顶是索引0(最小的负数,即实际的最大分数)

	    else:

	        # 如果堆中元素少于三个,则返回堆顶元素(取反后)作为最大的分数

	        target_score = -max_heap[0]  # 这实际上是堆中唯一的元素或两个元素中较大的那个的负数取反

	    

	    # 注意:上面的逻辑可以简化,因为我们总是知道堆的大小,并且堆要么有三个元素要么少于三个

	    # 下面的简化版本直接根据堆的大小返回结果

	    if len(max_heap) >= 3:

	        return -heapq.heappop(max_heap)  # 弹出堆顶元素(最小的负数,取反后得到第三大的分数)

	        # 注意:这里我们弹出了堆顶元素,但实际上我们不需要这个值,因为我们已经知道它是第三大的(在弹出之前)

	        # 我们只是为了简化逻辑而这样做,因为堆现在只包含两个最大的分数,但我们不需要它们

	        # 所以我们可以直接返回-max_heap[2](在弹出之前),这等于上面的-heapq.heappop(max_heap)(但更安全的是不弹出)

	        # 并直接使用-max_heap[1](因为堆已经更新,但现在我们不需要这样做)

	        # 为了保持一致性,我们还是使用弹出操作,但知道它实际上是不必要的

	        # 更简洁的做法是直接返回-max_heap[-1](在弹出操作之前,这是索引2的元素,因为我们知道堆有三个元素)

	        # 但由于我们已经弹出了元素,所以现在应该返回之前存储在target_score中的值(即-max_heap[2]的原始计算)

	        # 因此,下面的返回语句实际上是冗余的,因为上面的代码已经正确计算了target_score

	        # 这里只是为了说明逻辑而保留了这个返回语句,实际上应该删除或替换为上面的target_score赋值后的直接返回

	        # return -max_heap[-1] if we hadn't popped, but since we did, we use the previously computed target_score

	    else:

	        # 更简洁地,我们可以直接返回-max_heap[0](因为堆要么有一个元素要么有两个元素,且都是最大的)

	        # 但由于我们之前已经计算了target_score,所以这里还是使用它

	        return target_score  # 这实际上是-max_heap[0],因为我们知道堆顶元素是最大的负数的负数,即最大的分数

	 

	    # 但是上面的代码有些混乱,让我们简化它:

	    # 我们不需要弹出堆顶元素来计算第三大的分数,因为我们只需要知道堆的大小

	    # 如果堆有三个元素,我们返回第三个元素(取反后),否则我们返回堆顶元素(取反后)

	    # 下面的代码是简化后的版本:

	    if len(max_heap) == 3:

	        return -max_heap[2]  # 直接返回第三大的分数(取反后)

	    else:

	        return -max_heap[0]  # 返回最大的分数(取反后)

	 

	# 注意:上面的代码包含了一些冗余和混淆的部分,用于解释逻辑。

	# 下面的简化代码是最终的实现,它应该被用于实际的应用中:

	 

	def find_target_score_simplified(scores):

	    max_heap = []

	    for score in scores:

	        heapq.heappush(max_heap, -score)

	        if len(max_heap) > 3:

	            heapq.heappop(max_heap)

	    return -max_heap[2] if len(max_heap) == 3 else -max_heap[0]

	 

	# 示例用法

	scores = [100, 90, 80, 90, 70, 100, 60]

	target_score = find_target_score_simplified(scores)

	print(f"目标分数是: {target_score}")

注意:上面的堆实现部分包含了一些冗余和混淆的解释,用于阐述逻辑。在实际应用中,应该使用简化后的版本find_target_score_simplified。此外,由于我们总是至少推送一个分数到堆中,所以不需要检查堆是否为空。堆的大小将决定我们返回哪个分数。