我正在尝试编写一个给出非负整数列表的函数,将它们排列成最大可能的数字。
例如,给定[50, 2, 1, 9]
,最大的数字是95021
。
以下是我尝试解决问题的代码:
a = [50, 2, 1, 9]
a.sort()
ans = []
for i in range(len(a)-1,-1,-1):
ans.append(a[i])
print ''.join(map(str,ans))
但是,我得到50921
,因为50
是最大的,但它应首先显示9
。
答案 0 :(得分:18)
在Python 2中,您可以使用传递给sort
的适当比较函数来执行此操作。
#!/usr/bin/env python
''' Sort a list of non-negative integers so that
if the integers were converted to string, concatenated
and converted back to int, the resulting int is the highest
possible for that list
From http://stackoverflow.com/q/30140796/4014959
Written by PM 2Ring 2015.05.10
Python 2 version
'''
data = [
[50, 2, 1, 9],
[10, 1],
[2, 23, 21],
]
def mycmp(a, b):
a, b = str(a), str(b)
ab, ba = a + b, b + a
if ab == ba:
return 0
if ab < ba:
return -1
return 1
for a in data:
print 'In: ', a
a.sort(cmp=mycmp, reverse=True)
print 'Out:', a
print
<强>输出强>
In: [50, 2, 1, 9]
Out: [9, 50, 2, 1]
In: [10, 1]
Out: [1, 10]
In: [2, 23, 21]
Out: [23, 2, 21]
在Python 3中,sort
不再需要自定义比较功能。 scpio的答案显示了如何使用functools
将比较功能转换为关键功能,但这并不难做到&#34;手工&#34;。
#!/usr/bin/env python
''' Sort a list of non-negative integers so that
if the integers were converted to string, concatenated
and converted back to int, the resulting int is the highest
possible for that list
From http://stackoverflow.com/q/30140796/4014959
Written by PM 2Ring 2015.05.10
Python 3 compatible version
'''
from __future__ import print_function
class cmpclass(object):
def __init__(self, n):
self.n = str(n)
def __str__(self):
return self.n
def _cmp(self, other):
a, b = self.n, str(other)
ab, ba = a + b, b + a
if ab == ba:
return 0
if ab < ba:
return -1
return 1
def __lt__(self, other): return self._cmp(other) == -1
def __le__(self, other): return self._cmp(other) <= 0
def __eq__(self, other): return self._cmp(other) == 0
def __ne__(self, other): return self._cmp(other) != 0
def __gt__(self, other): return self._cmp(other) == 1
def __ge__(self, other): return self._cmp(other) >= 0
data = [
[50, 2, 1, 9],
[10, 1],
[2, 23, 21],
]
for a in data:
print('In: ', a)
a.sort(key=cmpclass, reverse=True)
print('Out:', a)
print('')
<强>输出强>
In: [50, 2, 1, 9]
Out: [9, 50, 2, 1]
In: [10, 1]
Out: [1, 10]
In: [2, 23, 21]
Out: [23, 2, 21]
我发布的以前的Python 3兼容版本实际上并不适用于Python 3:oops :!这是因为Python 3不再支持__cmp__
方法。因此,我已将旧的__cmp__
方法更改为_cmp
并将其用于实现所有6个方法rich comparison methods。
重要提示
我必须提到这个比较函数有点奇怪:它是不可传递的,换句话说,a> b和b&gt; c不必必然暗示a> c。这意味着在 .sort()
中使用它的结果是不可预测的。它似乎对我测试过的数据做了正确的事情,例如,它为[1, 5, 10]
的所有排列返回了正确的结果,但我想它真的不应该被信任到为所有输入都这样做。
保证工作的另一种策略是强力:生成输入列表的所有排列&amp;找到产生最大结果的排列。但希望有更高效的算法,因为生成大型列表的所有排列都相当慢。
正如Antti Haapala在评论中指出的那样,当比较由重复数字的相同序列组成的不同数字时,我的旧比较函数是不稳定的,例如123123和123123123.这些序列应该相等,我的旧函数没有&#39;那样做。最新修改解决了这个问题。
<强>更新强>
事实证明mycmp() / _cmp()
实际 是传递性的。它现在也很稳定,因为它可以正确处理ab == ba
案例,所以使用TimSort(或任何其他排序算法)是安全的。并且可以证明它与Antti Haapala的fractionalize()
关键函数具有相同的结果。
在下文中,我将使用大写字母表示列表中的整数,并且我将使用字母的小写字母来表示该整数中的位数。例如,a
是A
中的位数。我将_
用作中缀运算符来表示数字连接。例如,A_B
是int(str(A)+str(B)
;请注意A_B
有a+b
个数字。从算术,
A_B = A * 10**b + B
。
为了简洁起见,我将使用f()
来表示Antti Haapala的fractionalize()
关键功能。请注意f(A) = A / (10**a - 1)
。
现在为一些代数。我将它放在代码块中以保持格式简单。
Let A_B = B_A
A * 10**b + B = B * 10**a + A
A * 10**b - A = B * 10**a - B
A * (10**b - 1) = B * (10**a - 1)
A / (10**a - 1) = B / (10**b - 1)
f(A) = f(B)
So A_B = B_A if & only if f(A) = f(B)
Similarly,
A_B > B_A if & only if f(A) > f(B)
This proves that using mycmp() / _cmp() as the sort comparison function
is equivalent to using fractionalize() as the sort key function.
Note that
f(A_B) = (A * 10**b + B) / (10**(a+b)-1)
and
f(B_A) = (B * 10**a + A) / (10**(a+b)-1)
So f(A_B) = f(B_A) iff A_B = B_A, and f(A_B) > f(B_A) iff A_B > B_A
Let's see what happens with 3 integers.
f(A), f(B), f(C) are just real numbers, so comparing them is
transitive.
And so if f(A) > f(B) and f(B) > f(C) then f(A) > f(C).
This proves that mycmp() / _cmp() is also transitive.
Clearly, if f(A) > f(B) > f(C) then
A_B > B_A, B_C > C_B, A_C > C_A
Let B_C > C_B
For any A,
A * 10**(b+c) + B_C > A * 10**(b+c) + C_B
So A_B_C > A_C_B
i.e. adding the same integer to the beginning of B_C and C_B preserves
the inequality.
Let A_B > B_A
For any C,
(A_B) * 10**c + C > (B_A) * 10**c + C
So A_B_C > B_A_C,
i.e. adding the same integer to the end of A_B and B_A preserves the
inequality.
Using these results, we can show that
if f(A) > f(B) > f(C) then
A_B_C > A_C_B > C_A_B > C_B_A and
A_B_C > B_A_C > B_C_A > C_B_A.
This covers all 6 permutations of [A, B, C] and shows that A_B_C is the
largest possible integer for that list.
数学归纳式参数显示对任何列表进行排序
有限长度使用成对比较mycmp()
/ _cmp()
作为
比较函数或fractionalize()
作为关键函数就足够了
找到产生最大可能整数的排列
由数字串联产生。这个论点的细节将是
留给读者的练习。 :)
答案 1 :(得分:9)
One-liner使用Antti Haapala,PM 2Ring和Stefan Pochmann的见解:
from fractions import Fraction
sorted(a, key=lambda n: Fraction(n, 10**len(str(n))-1), reverse=True)
鉴于a = [50, 5, 51, 59, 2, 1, 9, 98]
:
[9, 98, 59, 5, 51, 50, 2, 1]
答案 2 :(得分:8)
这是一个丑陋的解决方案,无需将cmp
比较函数传递给sorted
即可运行。基本上,关键函数接受每个数字并计算具有该数字的有理数repeating decimals;
0 => 0
100 => 100/999 == 0.100100100...
10 => 10/99 == 0.1010101010...
1 => 1/9 == 0.1111111111...
11 => 11/99 == 0.1111111111...
12 => 12/99 == 0.1212121212...
9 => 9/9 == 1
99 => 99/99 == 1
999 => 999/999 == 1
0用排序键0排序为最小值,1后跟大多数零,键最接近0.1
,因此排序第二小。由数字9组成的数字都具有等于1
的排序键;如果您在9
之前或之后对99
进行排序并不重要。
使用这些值作为键进行排序必然会提供正确的输出,除非您使用的数字对于浮点精度来说太大了。 (可能早于2 ** 53
)
因此我们得到以下程序:
# for Python 2, not needed in Python 3
from __future__ import division
a = [50, 5, 51, 59, 2, 1, 9, 98]
def fractionalize(i):
divisor = 9
while divisor < i:
divisor = 10 * divisor + 9
return i / divisor
print(sorted(a, key=fractionalize, reverse=True))
哪个产生
[9, 98, 59, 5, 51, 50, 2, 1]
由于我们在这里基本上计算i / (10 ** ceil(log10(i + 1)) - 1)
,所以还可以编写以下oneliner:
from math import ceil, log10
print(sorted(a, key=lambda i: i and i/(10**ceil(log10(i+1))-1), reverse=True))
i and
部分保护除以零错误,以防0
为数字。
答案 3 :(得分:1)
我希望我在这方面的变化不大。我的输入被转换为字符串列表。我生成排列列表,创建列表列表,然后将子列表从最小到最大排序。最后,我采用排序列表的最后一个元素。
import itertools
digits = ['50', '2', '1', '9']
perms = itertools.permutations(digits)
sorted_numlist = sorted(perms)
print sorted_numlist[-1]
如果您更愿意拥有数字而不是元素列表......
import itertools
digits = ['11', '68', '4', '12']
perms = itertools.permutations(digits)
numlist = []
for sublist in perms:
permutated_num = "".join(sublist)
numlist.append(int(permutated_num))
sorted_numlist = sorted(numlist)
print sorted_numlist[-1]
第二个实际上也用于显示第一个是在列表上正确排序。
我对Python很陌生,并希望得到评论/改进。
答案 4 :(得分:0)
import functools
def cmpr(x, y):
xy = str(x) + str(y)
yx = str(y) + str(x)
return -1 if (xy > yx) else 1
a = [50, 2, 1, 9]
a.sort(key=functools.cmp_to_key(cmpr))
答案 5 :(得分:0)
最直接的方法是使用itertools.permutations()来模拟如何手动解决这个问题:
>>> from itertools import permutations, imap
>>> a = [50, 2, 1, 9]
>>> int(max(imap(''.join, permutations(map(str, a)))))
95021
答案 6 :(得分:0)
我很想从这里的所有python专家那里了解我的一线解决方案出了什么问题。 Leet代码网站不断拒绝失败的tcs,这在我的本地环境中效果很好。
from itertools import permutations as pm
def max_number(lst):
if all(v == 0 for v in nums):
return "0"
lst1 = [str(item) for item in lst]
return max([int(''.join(list(perm))) for perm in pm(lst, len(lst1))])
答案 7 :(得分:-1)
列表项
def create_largest_number(number_list):
res=''
for i in number_list:
res= res+ str(i)
new=''.join(sorted(res))
return new[::-1]
number_list=[23,45,67]
largest_number=create_largest_number(number_list)
print(largest_number)