Python数组拼接最大数代码中lambda排序键的原理问询
数组拼接最大数代码lambda排序键原理解析
先贴出待分析的完整实现代码:
def printLargest(self,arr): return "".join(sorted(arr,reverse=True,key=lambda _:_*18))
本次验证用的测试信息:
- 测试输入:
['3', '30', '34', '5', '9'] - 运行输出:
'9534330'
lambda语句的基础作用
传给sorted的key=lambda _:_*18是整个实现的核心排序规则:
- 表达式里的
_指代数组中的单个元素,注意这个实现默认输入arr里的元素已经是字符串类型,如果是整数直接做乘法会变成数值运算,逻辑完全错误。 - Python中字符串乘整数的语义是重复拼接自身,比如
'3'*2得到'33','30'*2得到'3030',所以这个lambda的作用就是把每个输入字符串重复拼接18次,生成一个长字符串作为排序时的比较依据。 - 配合
reverse=True参数,排序时会按照生成的长字符串的字典序从大到小重排原数组元素,最后直接拼接成结果返回。
排序键的设计逻辑
拼接最大数的核心判断规则其实很简单:任意两个字符串a、b,谁放前面能让拼接结果更大?只要比一下a+b和b+a哪个字典序更大,大的那个对应的前置元素就排前面。
要是直接按这个规则写,得写自定义的两两比较函数,Python3又去掉了sorted原生的cmp参数,得额外导入functools.cmp_to_key做转换,写起来啰嗦,性能也不如直接计算排序键好。
这个乘18次生成长串当key的写法是非常取巧的工程实现:只要把每个字符串重复足够多次,两个长串的字典序比较结果,和a+b/b+a的比较结果是完全等价的。选18作为重复倍数,是因为常规场景下(包括算法题、普通业务需求)单个整数转成字符串的长度不会超过18位,重复18次生成的串长度足够覆盖逐位比较的需求,不会出现比对到短串结束还分不出大小的情况。
结合测试用例的排序过程
拿测试输入的5个字符串举例,不需要真的生成完整的18次重复长串,只看前几位就能确定排序优先级:
'9'重复18次的串开头是'999999...',是所有串里字典序最高的,排第1位'5'重复18次的串开头是'555555...',仅比9对应的串小,排第2位'34'重复18次的串开头是'343434...',第一位是3,第二位是4,在所有3开头的串里最大,排第3位'3'重复18次的串开头是'333333...',第一位是3,第二位是3,比34的串小、比30的串大,排第4位'30'重复18次的串开头是'303030...',第一位是3,第二位是0,是3开头串里最小的,排第5位
按这个顺序拼接后得到'9'+'5'+'34'+'3'+'30' = '9534330',和实际运行结果完全一致。
这个写法有个很明确的边界:如果数组里存在长度超过18位的字符串元素,可能出现比较错误,遇到这种场景只要把重复倍数调到大于等于数组内最长字符串的长度就行。
内容的提问来源于stack exchange,提问作者Noobslayer
相关产品推荐
相关产品推荐

