排列数字以形成最大数 - 算法证明

arrange numbers to form largest number - proof of algorithm

众所周知 algorithmic problem,给定数字数组,例如[1, 20, 3, 14] 以尽可能形成最大数的方式排列数字,在本例中为 320141

SO 和其他站点上有很多解决方案,使用以下算法:

String[] strs = new String[nums.length];
for(int i=0; i<nums.length; i++){
    strs[i] = String.valueOf(nums[i]);
}

Arrays.sort(strs, new Comparator<String>(){
    public int compare(String s1, String s2){
        String leftRight = s1+s2;
        String rightLeft = s2+s1;
        return -leftRight.compareTo(rightLeft);

    }
});

StringBuilder sb = new StringBuilder();
for(String s: strs){
    sb.append(s);
}

return sb.toString();

它确实有效,但我找不到该算法的正式证明。 quora 上有一个答案,但我不会称其为正式证明。

谁能给我一张证明草图或参考一些书或文章?如何从原始问题得到这个解决方案?

PS我试图解决原来的问题,但我的解决方案是错误的,我无法正确解决,现在我无法完全理解解决方案。

这是算法的草图。对于您给定的列表:

[1, 20, 3, 14]

想一想如何找到最大的串联数。

对于最重要的数字,选择具有最大初始数字的数字。 (在示例中,选择 3,然后选择 20。因此答案以 320 开头。)

其余数字1和14的首位数字相同(即1)。接下来选哪个?这是算法的核心,compare 函数发挥作用的地方。它将构建数字并比较哪个在词汇上更大,即 114 与 141。return 语句中的负号将确保较大的数字在前。所以答案是 320141。

(该算法实际上并不比较初始数字,而是将字符串从词法上从最大到最小排序。)

关于符号:我将使用竖线分隔数字,所以它是 更容易看到数字序列和 结果数字 在 同时:3|20|14|1

让我们暂时假设关系——我们称它为 R<= 运算符表示——由比较定义 函数是一个全序。由表达式

决定
-(a+b).compareTo(b+a)

直观地说,如果我们有两个数字 abb|a 是 大于 a|bb 的排名应该高于 a,即它应该 出现在解决方案中 a 的左侧。如果a|b大于b|a,则相反 圆形的。如果a|b = b|a,顺序无关紧要。

需要注意的一件重要事情是,这种关系不仅影响两个 数字 ab 被孤立地考虑但也告诉我们一些事情 关于两个数字嵌入的结果数字:

如果a<=b,则x|a|b|y <= x|b|a|y

其中 xy 是 任意长度。换句话说:如果我们有一个数字序列 我们将两个相邻的数字 aba<=b 交换,结果 之后数字将大于或等于。

示例:3|14|20|1 <= 3|20|14|1 因为 14 <= 20

我们现在可以假设解决方案不是唯一的 我们的关系 R 暗示了一个矛盾:让我们假设 解决方案是一些不符合 R 的特定序列。因为 R 是一个 总顺序,我们可以通过交换重新排列数字以匹配 R 相邻元素直到顺序符合R。这种重新排序可以 与冒泡排序进行比较。但是,在每个交换操作中 引导我们进入新秩序,由此产生的数量增加!这是 显然是矛盾的,所以原来的顺序不可能是 解决方案。

剩下的就是R是一个全序,即 传递的,反对称的和总的。既然你要了草图 证明,我会省略这部分。关键部分是证明 传递性,即

a <= bb <= c 意味着 a <= c