>假设我有一个正整数数组;我想操纵顺序,以便结果数组的串联是可能的最大数字。例如[97, 9, 13]
结果为99713
; [9,1,95,17,5]
结果是9955171
。我不确定答案。
sorted(x, cmp=lambda a, b: -1 if str(b)+str(a) < str(a)+str(b) else 1)
直观地,我们可以看到,个位数的反向排序将导致最高的数字:
>>> ''.join(sorted(['1', '5', '2', '9'], reverse=True))
'9521'
所以反向排序应该有效。当输入中存在多位数代码段时,就会出现问题。在这里,直觉再次让我们在95
之前订购9
,在1
之前订购17
,但为什么会这样呢?同样,如果它们的长度相同,那么如何对它们进行排序就很清楚了:
95 < 99
96 < 97
14 < 17
那么,诀窍是"扩展"较短的数字,以便它们可以与较长的数字进行比较,并且可以按字典顺序自动排序。实际上,您需要做的就是重复该代码片段以超过最大长度:
- 比较
9
和95
:比较999
和9595
,因此999
是第一位的。 - 比较
1
和17
:比较111
和1717
,因此1717
是第一位的。 - 比较
132
和13
:比较132132
和1313
,因此132132
是第一位的。 - 比较
23
和2341
:比较232323
和23412341
,因此2341
是第一位的。
这是有效的,因为python只需要比较两个片段,直到它们在某处有所不同;而且在比较两个片段以确定它们需要以哪个顺序形成最大数字时,我们需要跳过(重复)匹配前缀。
您只需重复一个代码段,直到它比输入中的最长代码段 * 2 长,以确保在比较两个代码段时可以找到第一个不匹配的数字。
您可以使用key
参数来执行此操作sorted()
,但您需要先确定代码段的最大长度。使用该长度,您可以"填充"排序键中的所有代码段,直到它们超过该最大长度:
def largestpossible(snippets):
snippets = [str(s) for s in snippets]
mlen = max(len(s) for s in snippets) * 2 # double the length of the longest snippet
return ''.join(sorted(snippets, reverse=True, key=lambda s: s*(mlen//len(s)+1)))
其中,s*(mlen//len(s)+1)
填充代码段,其长度超过 mlen
。
这给出了:
>>> combos = {
... '12012011': [1201, 120, 1],
... '87887': [87, 878],
... '99713': [97, 9, 13],
... '9955171': [9, 1, 95, 17, 5],
... '99799713': [97, 9, 13, 979],
... '10100': [100, 10],
... '13213': [13, 132],
... '8788717': [87, 17, 878],
... '93621221': [936, 21, 212],
... '11101110': [1, 1101, 110],
... }
>>> def test(f):
... for k,v in combos.items():
... print '{} -> {} ({})'.format(v, f(v), 'correct' if f(v) == k else 'incorrect, should be {}'.format(k))
...
>>> test(largestpossible)
[97, 9, 13] -> 99713 (correct)
[1, 1101, 110] -> 11101110 (correct)
[936, 21, 212] -> 93621221 (correct)
[13, 132] -> 13213 (correct)
[97, 9, 13, 979] -> 99799713 (correct)
[87, 878] -> 87887 (correct)
[1201, 120, 1] -> 12012011 (correct)
[100, 10] -> 10100 (correct)
[9, 1, 95, 17, 5] -> 9955171 (correct)
[87, 17, 878] -> 8788717 (correct)
请注意,此解决方案是 a) 短 3 行,b) 也适用于 Python 3,而无需求助于 functools.cmp_to_key()
和 c) 不会暴力破解解决方案(这是 itertools.permutations
选项的作用)。
提示一:你连接字符串,而不是整数。提示二:itertools.permutations()
。
import itertools
nums = ["9", "97", "13"]
m = max(("".join(p) for p in itertools.permutations(nums)), key = int)
您可以按照提示使用 itertools.permutations,并在将它们与连接函数连接后使用 max 函数的键参数(它告诉将哪个函数应用于每个元素以确定最大值)。
首先使用字符串更容易。
我不喜欢蛮力方法。对于大型集合,它需要大量的计算。
您可以为排序的内置方法编写自己的比较函数,该方法将根据您在函数中输入的任何逻辑返回任何对的排序参数。
示例代码:
def compareInts(a,b):
# create string representations
sa = str(a)
sb = str(b)
# compare character by character, left to right
# up to first inequality
# if you hit the end of one str before the other,
# and all is equal up til then, continue to next step
for i in xrange(min(len(sa), len(sb))):
if sa[i] > sb[i]:
return 1
elif sa[i] < sb[i]:
return -1
# if we got here, they are both identical up to the length of the shorter
# one.
# this means we need to compare the shorter number again to the
# remainder of the longer
# at this point we need to know which is shorter
if len(sa) > len(sb): # sa is longer, so slice it
return compareInts(sa[len(sb):], sb)
elif len(sa) < len(sb): # sb is longer, slice it
return compareInts(sa, sb[len(sa):])
else:
# both are the same length, and therefore equal, return 0
return 0
def NumberFromList(numlist):
return int(''.join('{}'.format(n) for n in numlist))
nums = [97, 9, 13, 979]
sortednums = sorted(nums, cmp = compareInts, reverse = True)
print nums # [97, 9, 13, 979]
print sortednums # [9, 979, 97, 13]
print NumberFromList(sortednums) # 99799713
好吧,总是有蛮力方法...
from itertools import permutations
lst = [9, 1, 95, 17, 5]
max(int(''.join(str(x) for x in y)) for y in permutations(lst))
=> 9955171
或者这是对@Zah答案的改编,它接收整数列表并返回一个整数,如问题中所述:
int(max((''.join(y) for y in permutations(str(x) for x in lst)), key=int))
=> 9955171
您可以通过一些巧妙的排序来做到这一点。
如果两个字符串的长度相同,请选择两个字符串中较大的一个。容易。
如果它们的长度不同,请弄清楚如果将最佳组合附加到较短的组合上会是什么结果。由于较短的后面的所有内容都必须等于或小于它,因此您可以通过将短的附加到自身直到它与较长的大小相同来确定这一点。一旦它们的长度相同,您就可以像以前一样进行直接比较。
如果第二个比较相等,则您已经证明较短的字符串不可能比较长的字符串更好。根据它与它的配对,它仍然可能会变得更糟,所以更长的时间应该排在第一位。
def compare(s1, s2):
if len(s1) == len(s2):
return -1 if s1 > s2 else int(s2 > s1)
s1x, s2x = s1, s2
m = max(len(s1), len(s2))
while len(s1x) < m:
s1x = s1x + s1
s1x = s1x[:m]
while len(s2x) < m:
s2x = s2x + s2
s2x = s2x[:m]
return -1 if s1x > s2x or (s1x == s2x and len(s1) > len(s2)) else 1
def solve_puzzle(seq):
return ''.join(sorted([str(x) for x in seq], cmp=compare))
>>> solve_puzzle([9, 1, 95, 17, 5])
'9955171'
>>> solve_puzzle([97, 9, 13])
'99713'
>>> solve_puzzle([936, 21, 212])
'93621221'
>>> solve_puzzle([87, 17, 878])
'8788717'
>>> solve_puzzle([97, 9, 13, 979])
'99799713'
这应该比运行所有排列更有效。
import itertools
def largestInt(a):
b = list(itertools.permutations(a))
c = []
x = ""
for i in xrange(len(b)):
c.append(x.join(map(str, b[i])))
return max(c)