【发布时间】:2013-01-10 00:35:43
【问题描述】:
假设我有一个正整数数组;我想操纵顺序,以便结果数组的串联是可能的最大数字。例如[97, 9, 13] 导致99713; [9,1,95,17,5] 导致 9955171。我不确定答案。
【问题讨论】:
标签: python algorithm list python-2.7 integer
假设我有一个正整数数组;我想操纵顺序,以便结果数组的串联是可能的最大数字。例如[97, 9, 13] 导致99713; [9,1,95,17,5] 导致 9955171。我不确定答案。
【问题讨论】:
标签: python algorithm list python-2.7 integer
sorted(x, cmp=lambda a, b: -1 if str(b)+str(a) < str(a)+str(b) else 1)
【讨论】:
cmp 解决方案一样,不适用于 Python 3。
functools.cmp_to_key(),这会作弊)。
直观地说,我们可以看到,一位数的反向排序会导致最大的数字:
>>> ''.join(sorted(['1', '5', '2', '9'], reverse=True))
'9521'
所以反向排序应该可以工作。当输入中有多位 sn-ps 时,就会出现问题。在这里,直觉再次让我们在95 之前排序9 和17 在1 之前排序,但为什么会这样呢?同样,如果它们的长度相同,那么如何对它们进行排序就很清楚了:
95 < 99
96 < 97
14 < 17
然后,诀窍是“扩展”较短的数字,以便可以将它们与较长的数字进行比较,并且可以按字典顺序自动排序。实际上,您需要做的就是重复 sn-p 到超出最大长度:
9和95:比较999和9595,因此999是第一位的。1和17:比较111和1717,因此1717是第一位的。132 和13:比较132132 和1313,因此132132 是第一位的。23和2341:比较232323和23412341,因此2341是第一位的。这是可行的,因为 python 只需要比较两个 sn-ps,直到它们在某个地方有所不同;在比较两个 sn-ps 时,我们需要跳过(重复的)匹配前缀,以确定它们需要采用的顺序才能形成最大数。
你只需要重复一个sn-p直到它比输入中最长的sn-p * 2长,以保证你在比较两个sn-ps时能找到第一个不匹配的数字。
您可以使用 sorted() 的 key 参数来执行此操作,但您需要先确定 sn-ps 的最大长度。使用该长度,您可以“填充”排序键中的所有 sn-ps,直到它们长于最大长度:
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) 用自身填充 sn-p,使其长度超过 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 选项所做的)。
【讨论】:
[101, 10110]。我不明白“用自己填充 sn-p”的想法——如果自身引入的填充大于具有相同前缀的另一个术语的填充,则 ISTM 比较将误入歧途。
101 是一个匹配前缀,当你重复这些模式足够远时,你会发现它们的分歧点。对于您的反例,您找到了一种方法来克服我重复过去 mlen 的限制,因为 101101 仍然是 1011010110 的前缀,而重复较短的模式 3 次会显示差异:101101101 可针对1011010110。所以我对我需要重复元素多远的分析需要重新思考。我怀疑我需要在这里 加倍 mlen,然后将其用作上限。
mlen 确实可以解决这个问题;您确实需要重复最长的模式才能找到它是如何开始重复的;连接 787 和 78 时,在某处形成 778 或 787,并通过将 both 模式重复到最小长度,您可以为 key 方法生成两种形式并选择更大的。
234 和 234324),则顺序不再重要,[234, 234234] 和 [234234, 234] 的结果相同。
提示一:你连接的是字符串,而不是整数。
提示二:itertools.permutations().
【讨论】:
9 < 8 < 7 ... < 1 < 0
max( int(''.join(x)) for x in itertools.permutations( str(x) for x in seq ) )给出相同答案的排序解决方案。
9 应该在 95 之前,但 17 应该在 1 之前。我相信对第一个数字进行排序,然后对后面的数字(更高、缺失、更低)进行评分会起作用,但不是 100% 确定的。
import itertools
nums = ["9", "97", "13"]
m = max(("".join(p) for p in itertools.permutations(nums)), key = int)
您可以按照提示使用 itertools.permutations,并在将它们与 join 函数连接后使用 max 函数的 key 参数(它告诉将哪个函数应用于每个元素以确定最大值)。
以字符串开头更容易。
【讨论】:
我不喜欢这种蛮力方法。对于大型集合,它需要大量的计算。
您可以为 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
【讨论】:
嗯,总是有蛮力的方法......
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'
这应该比遍历所有排列更有效。
【讨论】:
[87, 17, 878] 和[97, 9, 13, 979]。
[1201, 120, 1],你和我的都失败了。
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)
【讨论】: