Скажем, у меня есть массив положительных целых чисел; Я хотел бы управлять порядком, чтобы конкатенация результирующего массива была наибольшим возможным числом. Например [97, 9, 13]
приводит к 99713
; [9,1,95,17,5]
приводит к 9955171
. Я не уверен в ответе.
Построение наибольшего числа возможно путем перегруппировки списка
Ответ 1
sorted(x, cmp=lambda a, b: -1 if str(b)+str(a) < str(a)+str(b) else 1)
Ответ 2
Интуитивно мы видим, что обратный вид чисел с одной цифрой приведет к наивысшему числу:
>>> ''.join(sorted(['1', '5', '2', '9'], reverse=True))
'9521'
поэтому обратная сортировка должна работать. Проблема возникает, когда на входе есть многозначные фрагменты. Здесь интуиция снова позволяет нам заказывать 9
до 95
и 17
до 1
, но почему это работает? Опять же, если бы они были одинаковой длины, было бы ясно, как их сортировать:
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) не выполняет команду brutforce (что делает опция itertools.permutations
).
Ответ 3
Подсказка: вы объединяете строки, а не целые числа.
Подсказка: itertools.permutations()
.
Ответ 4
import itertools
nums = ["9", "97", "13"]
m = max(("".join(p) for p in itertools.permutations(nums)), key = int)
Вы можете использовать itertools.permutations в качестве намеченного и использовать ключевой аргумент функции max (которая сообщает, какая функция применяется к каждому элементу, чтобы решить максимум) после того, как вы соедините их с функцией объединения.
С самого начала проще работать со строками.
Ответ 5
Мне не нравится подход грубой силы к этому. Это требует большого количества вычислений для больших наборов.
Вы можете написать свою собственную функцию сравнения для sorted встроенного метода, который вернет параметр сортировки для любой пары на основе любого логику, которую вы ввели в функцию.
Пример кода:
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
Ответ 6
Ну, всегда есть подход грубой силы...
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
Ответ 7
Вы можете сделать это с помощью некоторой умной сортировки.
Если две строки имеют одинаковую длину, выберите более крупную из двух, чтобы она была первой. Легко.
Если они не имеют одинаковой длины, выясните, что было бы результатом, если бы лучшая комбинация была добавлена к более короткой. Поскольку все, что следует за более коротким, должно быть равно или меньше, чем это, вы можете определить это, добавив короткий к себе, пока он не будет иметь тот же размер, что и более длинный. Как только они имеют одинаковую длину, вы делаете прямое сравнение по-прежнему.
Если второе сравнение равно, вы доказали, что более короткая строка не может быть лучше, чем более длинная. В зависимости от того, что он в паре с ним, все еще может ухудшиться, поэтому дольше нужно идти первым.
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'
Это должно быть гораздо более эффективным, чем выполнение всех перестановок.
Ответ 8
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)