排序较大的List时超时异常

时间:2018-05-22 13:11:19

标签: java sorting collections

我试图从big-sorting解决HackerRank问题。我有以下解决方案:

static String[] bigSorting(String[] unsorted) {

    List<BigInteger> newValues = new ArrayList<BigInteger>();

    String[] newValuesArray = new String[unsorted.length];
    for (int i = 0; i < unsorted.length; i++) {
        newValues.add(new BigInteger((unsorted[i])));
    }

    Collections.sort(newValues);

    for (int i = 0; i < newValues.size(); i++) {
        newValuesArray[i] = newValues.get(i).toString();
    }
    return newValuesArray;
}

虽然如果输入很短,我的解决方案仍在工作,但是对于冗长的输入,它会给出TimeoutException

当我开始知道导致问题的测试用例是:

total input = 7693
And Values :
123121
22
2
23123
12312
2
8400195277734975809347292766456055069919837818826921595732345474832683881284408515491064519242069257576624629524016550879441266062080977804902962370685876553901611732
And So on...until 7693 values

所以我在这里有关于Collections.sort(newValues);天气导致这个问题的问题,因为有大量的数字要排序,所以可能需要时间或其他东西?

请在下面找到关于输出的快照:

enter image description here

这就是输入

enter image description here

2 个答案:

答案 0 :(得分:2)

不是使用BigInteger,而是直接对String进行排序。

使用String的自然顺序不会起作用,因为2将在10之后出现。

但是,您可以定义支持数字Comparator<String>的自己的StringComparator compare方法首先会比较String的长度。如果第一个String更短,它将返回-1,如果它更长,它将返回1.

如果两个String具有相同的长度,您将迭代两个String的字符并一次比较一个字符。如果所有字符都相等,则返回0.否则返回-1或1,具体取决于String s中不同的第一个字符在第一个String中是否更小或更大。

以下是Comparator compare方法的可能实施方式:

public int compare(String one, String two) {
    if (one.length != two.length)
        return one.length() - two.length();       
    for (int i = 0; i < one.length; i++) {
        char c1 = one.charAt(i);
        char c2 = two.charAt(i);
        if (c1 != c2) {
            return c1 - c2;
        }
    }
    return 0;
}

然后:

static String[] bigSorting(String[] unsorted) {
    Comparator<String> comparator = ... // the above mentioned Comparator
    Arrays.sort(unsorted, comparator);
    return unsorted;
}

答案 1 :(得分:1)

让我们将您的代码分成几个部分:

List<BigInteger> newValues = new ArrayList<BigInteger>();

String[] newValuesArray = new String[unsorted.length];
for (int i = 0; i < unsorted.length; i++) {
    newValues.add(new BigInteger((unsorted[i])));
}

本节的表现取决于两件事:

  1. unsorted
  2. 的大小
  3. sorted
  4. 中字符串的长度

    字符串长度很重要的原因是将十进制字符串转换为BigInteger使用的内部表示是很昂贵的。对于具有D位的单个字符串,时间复杂度为O(D 2 )。因此总体复杂度为O(ND 2 )。

    Collections.sort(newValues);
    

    此分类步骤通常为O(NlogN),或O(NlogND),最差情况 1

    for (int i = 0; i < newValues.size(); i++) {
        newValuesArray[i] = newValues.get(i).toString();
    }
    

    由于toString()电话,这是O(ND 2 )。

    因此,从总体上看,我们的典型复杂度为O(ND 2 + NlogN)。

    关于复杂性的分析是非常粗糙和准备好的。如果我犯了任何重大错误,请发表评论......

    我们从上面的分析中可以看出,从字符串到BigInteger和返回的转换成本可能主导排序成本。特别是如果大多数数字有多位数。

    我们能避免这种情况吗?是!可以编写一个Comparator<String>来比较十进制数而不将它们转换为二进制数。

    我们可以优化的第二件事是排序。

    • 在某些情况下,Collections::sort方法实际上会将集合复制到数组中,对数组进行排序,然后将已排序的数组复制回列表。

    • 另一种名为Arrays::sort的方法。如果您使用此功能,则可以避免使用一个或多个列表&lt; - &gt;阵列复制步骤。

    • 还有另一种名为Arrays::parallelSort的方法。如果有可用的C核,使用这种方法可以提高(最多)C倍速。

    1 - 典型情况发生在列表中的数字明显不同时,您通常可以在O(1)中比较它们中的一对。最坏的情况是当nnumber都相同(或接近)时,比较通常是O(D)。