python新手刷题之:红包运气排行榜 | 豆包MarsCode AI刷题

106 阅读4分钟

问题描述:

小C参与了一场抢红包的游戏,现在他想要对所有参与抢红包,的人进行一次运气排名。排名规则如下:抢到的金额越多,排名越靠前;如果两个人抢到的金额相同,则按照他们抢红包的顺序进行排名。比如,如果小C和小U抢到的金额相同,但小C比小U先抢,则小C排在小U前面。

测试样例:

输入:n = 4, s = ["a", "b", "c", "d"], x = [1, 2, 2, 1] 输出:['b', 'c', 'a', 'd']
输入:n = 3, s = ["x", "y", "z"], x = [100, 200, 200]) 输出:['y', 'z', 'x']
输入:n = 5, s = ["m", "n", "o", "p", "q"], x = [50, 50, 30, 30, 20]) 输入:['m', 'n', 'o', 'p', 'q']

解题过程:

由于接触编程时的第一个语言是C语言,所以面对编程问题时第一反应就是以C语言处理问题的方式来思考。那么,以我习惯的思路来看,对于这个题目,本质上就是排序,但因为不光要对数字排序,还要同步调整一份名单,所以还需要在排序的过程中同步记录下索引的变化,最后按照改变后的索引重新排列名单,就可以实现问题的求解。接下来要做的就是编程实现上述思路,但是要使用python。最终,在网络上查阅了一些资料,并在AI的帮助下,得到了如下代码:

def solution(n: int, s: list, x: list) -> list:
    # 初始化数据结构
    people = [(money[i], i) for i in range(len(name))]

    # 排序
    people.sort(key=lambda p: (-p[0], p[1]))

    # 提取结果
    result = [name[p[1]] for p in people]

    return result

上述代码中,比较不好理解的是sort函数的参数key。sort函数的作用是对列表进行排序,且默认为升序排序,而参数key的作用是指定一个函数(或其他可调用对象),该函数将在进行比较之前被调用在每个列表元素上。这里使用了lamda函数创建了一个功能简单的函数,即对people元组的第一项做取反操作。那么最终排序后的结果就变成了按照金额数目降序,按照下面的写法也可以达到这种效果:

people.sort(key=lambda x: x[0], reverse=True)

但当我提交后却发生了错误,错误案例如下:

输入:n = 12, s = ["aa","aaaaaaa","aaaa","aaaa","aaaa","aaaaaaaaaa","aaaaaaaaa","aaaa","aaaaaaaaaa","aaaaaaaaa","aaaaa","aaaa"], x = [17,14,11,2,8,16,14,17,10,6,5,12]) 输出:["aaaa","aaaaaaaaaa","aaaaaaaaa","aa","aaaaaaa","aaaaa"]

仔细分析案例发现,名单中出现了重复,所以再补上去重部分就行,完善后的代码如下:

def solution(n: int, s: list, x: list) -> list:
    # 合并同类项
    name = []
    money = [0] * n
    for i in range(n):
        if s[i] not in name:
            name.append(s[i])
        money[name.index(s[i])] += x[i]

    # 初始化数据结构
    people = [(money[i], name[i]) for i in range(len(name))]
    
    # 排序
    # people.sort(key=lambda p: (-p[0], p[1]))
    people.sort(key=lambda x: x[0], reverse=True)
    
    # 提取结果
    result = [p[1] for p in people]
    
    return result

其中,我开辟了两个列表name和money,name用来存储去重后的名单,money则将相同来源的数据加到了一起。具体来说,首先通过索引遍历名单,当名称第一次出现时就将其加入name列表中,之后按名称在name中的索引向money中并入对应金额即可,index函数就是用来查询索引的,它会返回目标元素第一次出现时的下标。

另外,我还优化了一下之前的代码。改动的地方不多,就两处(11行和18行),之前的代码中,重新构建的元组包含的是金额和索引,再根据排序后的索引提取名单。改动之后,元组包含的是金额和名称,排序之后直接按序提取名称即可。有一点需要注意的是,排序规则需要稍微改一下,用上文中提到的第二种方法。因为第一种方法里,元组的第二项实际是升序,这种做法对于本来就是按照顺序的0,1,2,···索引没有影响,但换成字符串后,如果第一项相同,则会根据字符串再次排序,此时的结果会产生偏差。第二种方法将排序规则指定为对元组的第一项降序,所以不会受到元组第二项的影响。

提交后不再报错,顺利完成解题。