编写一个函数,给定一个非负整数列表,将它们排列成最大可能的数字。例如,给定[0,1,2,3],最大形成的数字是3210.
逻辑我理解:
我们比较两个数字XY(在X的末尾附加Y)和YX(在Y的末尾附加的X)。如果XY较大,则X应该在输出Y之前,否则Y应该在之前。例如,让X和Y为542和60.为了比较X和Y,我们比较54260和60542.由于60542大于54260,我们将Y放在第一位。我也可以为此编写代码。
这个解决方案让我感到惊讶:
#include <stdio.h>
#include<stdlib.h>
int swap(const void *c, const void *d) {
int n1 = *(int*)c;
int n2 = *(int*)d;
int a = pow(10, floor(log10(n2)) + 1) * n1 + n2;
int b = pow(10, floor(log10(n1)) + 1) * n2 + n1;
if (n1 == 0) return 1;
if (a < b) return 1;
return 0;
}
int main() {
int t = 0, tc = 0;
scanf("%d", &t);
for(tc = 1; tc <= t; tc++) {
int n;
scanf("%d",&n);
int arr[n];
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
qsort(arr, n, sizeof(int), swap);
for (int i = 0; i < n; i++)
printf("%d", arr[i]);
printf("\n");
}
return 0;
}
令我惊讶的是,它通过了所有测试用例。任何人都可以向我解释这个逻辑吗?
答案 0 :(得分:2)
这完全符合您的描述:
int a = pow(10, floor(log10(n2)) + 1) * n1 + n2;
int b = pow(10, floor(log10(n1)) + 1) * n2 + n1;
如果我们传入X
和Y
,则a
为XY
,b
为YX
。
如果你连接2和34,你需要将2乘以100(得到200),然后加34(得到234)。 100来自哪里?它是10的四位数的幂。为了得到位数,我们计算基数为10的对数为34并将其四舍五入。
所以:
log10(34) ~= 1.5
floor(log10(34)) == 1
floor(log10(34)) + 1 == 2
10^2 = 100
,现在我们知道在添加第二个数字之前将第一个数字相乘的内容。
第二行对相反顺序的变量执行相同的操作(计算YX
连接)。
最后,如果&lt;&lt; b,否则为0。这使它成为排序函数的工作比较器:
if (a < b) return 1;
修改强>
我不确定这条线在做什么:
if (n1 == 0) return 1;
我认为这可能会保护我们免受log10(0)
的影响。 (我不确定返回的是什么......数学结果是负无穷大。)
基本上,比较器中的结果是“如果n2
为0则首先放n1
”, 总是正确的。 (我只是不确定为什么需要它。)
答案 1 :(得分:1)
我们假设数组arr[]
是您问题的解决方案,即其元素的排列方式是产生最大结果M
。因此,交换任意数组元素i
和j
不会产生大于M
的结果。
考虑比较比较器函数i
中的任意索引j
和swap
及其周围的数字:
XXXXXXXX IIIIII XXXXXXXXXXXXXXXX JJJJJJ XXXXXXXXX
-------- ------ ---------------- ------ ---------
arr[...] arr[i] arr[...] arr[j] arr[...]
请注意,如果IIIIII
块在JJJJJJ
块之前进行排序,则无论X
块的内容如何,它都会在它之前继续排序。因此,在使用此比较对整个数组进行排序时,单独比较arr
的各个元素会产生最佳解决方案。
您的比较器实现使用&#34;十进制移位&#34;执行此逻辑:如果您要在x
的数字后面添加y
的数字,则需要十进制移位{{1 } y
中的位数。 x
中的位数可以确定为log 10 (x); k位置左移小数是通过将x
乘以10 k 来实现的。
注意:此行
y
在调用十进制对数之前,应位于顶部。还应该有另一行
if (n1 == 0) return 1;
确保我们不将零传递给if (n2 == 0) return 0;
。
答案 2 :(得分:0)
代码中做了什么,
输入&amp;输出部分很容易理解。
现在使用接受比较功能的qsort完成排序。在代码中虽然函数名为swap,但它实际上是一个比较函数 - 当第一个元素大于第二个元素时返回1。否则返回0.例如is 54 > 45?
和is 45>54?
现在,为什么降序排序会得到应得的输出?让我们看一个例子:
54&gt; 45,这意味着如果大数字是左侧位置,则数字更大。降序排序会保留更大的数字。
答案 3 :(得分:0)
您已经对发布的代码的工作原理有了很好的解释。但是,应该注意的是,只要任何数字的十进制移位版本超过最大可表示int
,该方法就会出现溢出。如果我们假设一个32位int
,那么它有10位数(2147483647),因此比较相对较小的数字,如32412和12345将导致问题。
作为替代方案,我们可以使用递归函数直接比较数字。设两个数字分别为n1
和n2
,分别为d1
和d2
位数。我们的比较函数需要处理三种情况:
如果d1 == d2
我们直接比较n1
和n2
,例如345和463
如果d1 < d2
我们将n1
与d1
的{{1}}高位数进行比较,例如对于37和398,我们比较37和39.如果它们相等,我们递归地将n2
与n2的n1
低位数进行比较。因此,对于37和378,我们将比较37和8。
如果d2-d1
我们可以交换d1 > d2
和n1
并按照案例2进行比较,但我们必须反转结果的顺序。
这里有一些代码可供说明。
n2