小C参与了一场抢红包的游戏,现在他想要对所有参与抢红包的人进行一次运气排名。排名规则如下:抢到的金额越多,排名越靠前;如果两个人抢到的金额相同,则按照他们抢红包的顺序进行排名。比如,如果小C和小U抢到的金额相同,但小C比小U先抢,则小C排在小U前面。
学习笔记:如何通过排序实现基于金额和顺序的排名
一、问题分析
小C参与了一场抢红包的游戏,游戏规则是每个玩家抢到不同金额的红包。小C希望根据抢到的金额来给每个人排个顺序。如果两个人抢到的金额相同,则根据他们的抢红包顺序来排序。简单来说,金额多的排前面,金额相同的按照谁先抢谁排前面。
这个问题可以归结为一种基于金额和顺序的排序问题。我们需要设计一个排序算法,使得排序首先依据金额大小,金额相同则依据玩家抢红包的顺序来决定排名。
二、如何设计解法
1. 数据结构的选择
在这个问题中,输入的主要数据有两部分:
s
:表示每个参与者的名字,顺序表示他们抢红包的顺序。x
:表示每个参与者抢到的金额。
为了排序,我们需要将这两个数据结合起来,因此一个合适的方式是使用元组。我们可以将每个参与者的名字和对应的金额组成一个元组 (name, amount)
。通过这种方式,我们可以同时处理参与者的名字和金额,方便后续排序。
2. 排序规则
排序的规则是:
- 主要排序条件:按照抢到的金额
amount
进行排序,金额多的排前面。 - 次要排序条件:如果金额相同,则按照抢红包的顺序进行排序,即按照在
s
列表中的顺序来排列。
为了实现这一规则,可以利用 Python 的 sorted
函数和 lambda
表达式进行排序:
- 使用
-amount
来实现金额的降序排序(Python 默认是升序排序)。 - 使用原始顺序
s.index(name)
来保证相同金额时,按照最初出现的顺序排序。
3. 最终输出
排序完成后,我们只需要从排序后的数据中提取名字部分,并返回最终的排名结果。
三、代码实现
def solution(n: int, s: list, x: list) -> list:
# 将名字和金额组合成元组列表
combined = list(zip(s, x))
# 根据金额降序排序,如果金额相同则按顺序排列
combined.sort(key=lambda item: (-item[1], s.index(item[0])))
# 提取排序后的名字并返回结果
return [name for name, _ in combined]
# 测试样例
if __name__ == "__main__":
print(solution(4, ["a", "b", "c", "d"], [1, 2, 2, 1]) == ['b', 'c', 'a', 'd'])
print(solution(3, ["x", "y", "z"], [100, 200, 200]) == ['y', 'z', 'x'])
print(solution(5, ["m", "n", "o", "p", "q"], [50, 50, 30, 30, 20]) == ['m', 'n', 'o', 'p', 'q'])
四、代码解释
-
数据组合:
combined = list(zip(s, x))
:将名字列表s
和金额列表x
组合成一个元组列表,使得每个元组的第一个元素是名字,第二个元素是对应的金额。例如:[('a', 1), ('b', 2), ('c', 2), ('d', 1)]
。 -
排序:
combined.sort(key=lambda item: (-item[1], s.index(item[0])))
:我们使用sorted
的key
参数来指定排序规则。-item[1]
:按照金额降序排序(item[1]
是每个元组中的金额)。s.index(item[0])
:如果金额相同,则根据名字在原列表中的顺序进行排序。
-
提取名字:
return [name for name, _ in combined]
:从排序后的元组列表中提取出名字部分,返回最终排名顺序。
五、复杂度分析
-
时间复杂度:
- 将名字和金额结合的操作是
O(n)
,其中n
是参与者的数量。 - 排序操作的时间复杂度是
O(n log n)
,这是主要的时间开销。 - 总的时间复杂度为
O(n log n)
。
- 将名字和金额结合的操作是
-
空间复杂度:
- 存储组合后的元组列表需要
O(n)
空间。 - 最终输出的名字列表也是
O(n)
空间。 - 总的空间复杂度是
O(n)
。
- 存储组合后的元组列表需要