我试图从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);
天气导致这个问题的问题,因为有大量的数字要排序,所以可能需要时间或其他东西?
请在下面找到关于输出的快照:
这就是输入
答案 0 :(得分:2)
不是使用BigInteger
,而是直接对String
进行排序。
使用String
的自然顺序不会起作用,因为2将在10之后出现。
但是,您可以定义支持数字Comparator<String>
的自己的String
。 Comparator
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])));
}
本节的表现取决于两件事:
unsorted
。sorted
。字符串长度很重要的原因是将十进制字符串转换为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)。