问题:给定一个可以包含重复项的正整数数组,找到通过连接整数获得的最小数。例如:[3, 32, 321]
返回321323
除了尝试所有n!连接排列,我似乎无法找到解决这个问题的好方法。我知道下面有一个很好的解决方案,但我很难理解为什么它是真的(如果你想尝试解决这个问题,请停止阅读):
我已经阅读了一个解决方案,我们可以使用比较器对数组进行排序,比较器通过比较连接m
和连接的数值来比较两个数字n
和mn
nm
,排序的数组将是给出最小数字的串联,但我无法弄清楚为什么这是真的。有什么想法吗?
答案 0 :(得分:2)
你可以使用类似于冒泡排序的东西来解决这个问题。
首先,我们注意到最终结果的长度是固定的。
其次,结果是您可以创建的最小词典字符串(因为所有可能的字符串的长度是固定的,所以最小字典也是最小数字)。
假设我们有两个号码n
和m
,如果nm< mn,所以n应该总是在m的前面。因为如果我们有一个字符串是m ... n,那么我们总是可以通过将其交换为n ... m来获得更小的字符串。
所以我们继续交换数字直到没有任何东西可以交换,这是最终的答案
答案 1 :(得分:0)
这是一个数学问题,而不是计算机问题。
将连接操作定义为C(a1,... an),其中(a1,... an)是有序数组。然后C满足
C(a1,... an)= C(C(a1,... ax),C(a(x + 1),... an))
对于任何1< x< Ñ
使用数学归纳法,将F定义为处理n个变量数组的函数。
F(2)= min(C(a1,a2),C(a2,a1))定义明确。
对于F(n),给定F(n-1)被最小化,问题变为找到最佳位置,使得F(n)最小化。然后很容易证明
对于C(ax,an)>的任何斧头。 C(an,ax),C(a1,... ax,an,a(x + 1),... a(n-1))< C(a1,... a(x - 1),an,ax,a(x + 1),... a(n - 1))。
对于C(ax,an)< C(an,ax),C(a1,... ax,an,a(x + 1),... a(n-1))> C(a1,... a(x - 1),an,ax,a(x + 1),... a(n - 1))。
所以最好的解决方案是插入一个位置C(ax,an)< C(an,ax)和C(a(x + 1),a)> C(an,a(x + 1))。因此,您描述的算法成立。
答案 2 :(得分:0)
如果它们都是单位数字,解决方案很简单:对它们进行排序并选择结果中最重要(最左边的数字)的最小数字。例如在3之前选择2因为23小于32。
类似于多位数字,按最左边的数字排序。例如在45之前选择123,因为12345小于45123。
最棘手的部分是关系。如果最左边的数字相同,则比较第二个数字,然后比较第三个数字......例如因为32134小于34321,所以在34之前选择321。
最后,如果有一个平局并且你的数字用完了怎么办?因为3213小于3321,所以在3之前选择321。
因此,使用Java作为一种语言,使用这些规则编写一个Comparator(请注意,您可能更好地将数字视为字符串,而不是数字),排序,然后连接。其他语言也类似。
比较器的Java代码: See also Gist with a main() for testing请注意,我能够重组并简化规则。此代码可能更好地针对速度进行了优化。 (注意:假设所有的整数首先转换为字符串以提高效率)
public class SO25396760 implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
int minLength = Math.min(s1.length(), s2.length());
int result = s1.substring(0, minLength).compareTo(s2.substring(0, minLength));
if (result != 0)
return result;
int lenDiff = s1.length() - s2.length();
if (lenDiff == 0)
return 0; // Strings are equal
if (lenDiff < 0)
return compare(s1, s2.substring(minLength));
else
return compare(s1.substring(minLength), s2);
}
}
当输入为{“321”,“3”,“35”,“321334”,“333”,“2”}时;排序的数组是 [2,321,321334,3,333,35] 和连接的值是 2321321334333335.通过检查测试这是最小的。
答案 3 :(得分:0)
让<'
成为有问题的比较器,以便m <' n
当且仅当。{
mn < nm
。 假设<'
是strict weak
ordering ,
其他答案是关于为什么按<'
排序的原因
好主意。这是一个仔细的证据。假设相反的是两个
(可能是不相邻的)输入字符串m <' n
是乱序的,所以
输出看起来像
...n...p...m...
通过对n
和m
之间距离的归纳,我们证明了这一点
输出不是最小的。在基本情况下,当n
位于m
旁边时,我们
可以交换它们。自mn < nm
以来,新输出较小。电感,
让p
成为n
和m
之间输出中的输入字符串。
如果是p <' m
,那么p <' n
是传递性的。如果p <' n
,那么我们调用
n
和p
上的归纳假设,它比n
和m
更近
n <' p
。如果是m <' p
,那么m <' p
是传递性的。如果p
,那么我们
调用m
和n
上的归纳假设,它们比...更近
m
和n
。如果这些情况都不适用,那么p
和p
就是
无与伦比,而m
和n
是无与伦比的。通过传递性
不可比性,m
和n <' m
是无法比拟的,这与之相矛盾
事实是m
,因此前四个案例中的一个适用。
确定最小输出中输入字符串的顺序
最多在等价块内置换等效字符串。以来
等同于n
的{{1}}意味着mn = nm
,我们得到相同的输出
无论排列如何,这个输出因此是最小的。
正确性证明的有趣部分证明<'
首先是严格的弱序。事实上,除非是这样
我们排除了空字符串,这会造成严重破坏。对于所有非空的
字符串m
,让key(m)
成为由m
组成的无限字符串
经常无限重复。表明<'
是一个严格的弱序
在非空字符串上,只有{if}才足以显示m <' n
key(m) < key(n)
。
首先假设m <' n
。然后是mn < nm
。让|m|
为长度
m
的{{1}},重复(m^|n|)(n^|m|) < (n^|m|)(m^|n|)
应用不等式mn < nm
。以来
|m^|n|| = |m||n| = |n^|m||
,我们得出m^|n| < n^|m|
的结论
key(m) < key(n)
。
现在假设m <' n
不成立。如果nm < mn
,那么我们认为是
在key(n) < key(m)
之前,因此key(m) < key(n)
没有
保持。否则,mn = nm
。自(m^|n|)(n^|m|) = (n^|m|)(m^|n|)
以来,我们
得出结论m^|n| = n^|m|
,因而key(m) = key(n)
。