从阵列形成的最大数字(了解解决方案)

时间:2017-08-20 16:32:47

标签: arrays algorithm sorting quicksort

编写一个函数,给定一个非负整数列表,将它们排列成最大可能的数字。例如,给定[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;
}

令我惊讶的是,它通过了所有测试用例。任何人都可以向我解释这个逻辑吗?

4 个答案:

答案 0 :(得分:2)

这完全符合您的描述:

int a = pow(10, floor(log10(n2)) + 1) * n1 + n2;
int b = pow(10, floor(log10(n1)) + 1) * n2 + n1;

如果我们传入XY,则aXYbYX

如果你连接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。因此,交换任意数组元素ij不会产生大于M的结果。

考虑比较比较器函数i中的任意索引jswap及其周围的数字:

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)

代码中做了什么,

  1. 输入数组
  2. 按降序排序
  3. 输出
  4. 输入&amp;输出部分很容易理解。

    现在使用接受比较功能的qsort完成排序。在代码中虽然函数名为swap,但它实际上是一个比较函数 - 当第一个元素大于第二个元素时返回1。否则返回0.例如is 54 > 45?is 45>54?

    现在,为什么降序排序会得到应得的输出?让我们看一个例子:

    54&gt; 45,这意味着如果大数字是左侧位置,则数字更大。降序排序会保留更大的数字。

答案 3 :(得分:0)

您已经对发布的代码的工作原理有了很好的解释。但是,应该注意的是,只要任何数字的十进制移位版本超过最大可表示int,该方法就会出现溢出。如果我们假设一个32位int,那么它有10位数(2147483647),因此比较相对较小的数字,如32412和12345将导致问题。

作为替代方案,我们可以使用递归函数直接比较数字。设两个数字分别为n1n2,分别为d1d2位数。我们的比较函数需要处理三种情况:

  1. 如果d1 == d2我们直接比较n1n2,例如345和463

  2. 如果d1 < d2我们将n1d1的{​​{1}}高位数进行比较,例如对于37和398,我们比较37和39.如果它们相等,我们递归地将n2与n2的n1低位数进行比较。因此,对于37和378,我们将比较37和8。

  3. 如果d2-d1我们可以交换d1 > d2n1并按照案例2进行比较,但我们必须反转结果的顺序。

    < / LI>

    这里有一些代码可供说明。

    n2