如何解决Arrays.sort与使用Map进行排序
我有一个必须遍历具有字符串列表的数组的要求:
String[] arr = {"abc","cda","cka","snd"}
并匹配字符串"bca"
,忽略字符顺序,这将返回数组中的true
("abc"
)。
要解决此问题,我有两种方法:
- 使用
Arrays.sort()
对两个字符串进行排序,然后使用Arrays.equals对其进行比较。 - 创建2个哈希图,并在字符串中添加每个字母的频率,然后最后使用equals方法比较两个char图。
我读到使用Arrays.sort()
方法的复杂性更高。因此,考虑使用第二种方法,但是当我同时运行两种代码时,第一种方法花费的时间却很少。
任何建议为什么会这样?
解决方法
Time Complexity仅告诉您,该方法如何在(大量)较大的输入下进行扩展。它不会告诉您哪种方法更快。
由于时间复杂度,对于较小的输入大小(字符串长度和/或数组长度),解决方案极有可能会更快,但对于较大的大小,解决方案的伸缩性很可能很差。但是,即使输入大小的自然限制阻止了时间复杂度更好的算法变得更快,您甚至可能从未遇到过这一点。
您没有显示方法的代码,但您的第一个方法很可能在字符串上调用了类似toCharArray()
的方法,随后是Arrays.sort(char[])
。这意味着排序对原始数据进行操作。
相反,当您的第二种方法使用HashMap<Character,Integer>
来记录频率时,将受到装箱开销(对于字符和计数)的限制,并且还会使用需要处理的更大的数据结构。
因此,对于较小的字符串和数组,散列方法的速度较慢也就不足为奇了,因为它具有较大的固定开销,并且还取决于大小(O(n)
)。
因此,第一种方法必须遭受O(n log n)
时间复杂度的严重影响才能得出此结果。但这不会发生。一般而言,时间复杂度是最坏的情况。如this answer中所述,the documentation of Arrays.sort
中指定的算法不应被视为理所当然。当您调用Arrays.sort(char[])
并且数组大小超过某个阈值时,实现将转换为Counting Sort,时间复杂度为O(n)(但暂时使用更多的内存)。
因此,即使使用较大的字符串,您也不会遭受时间复杂性恶化的困扰。实际上,计数排序与频率图具有相似之处,但通常效率更高,因为它使用int[]
数组而不是HashMap<Character,Integer>
来避免装箱开销。
让我们分解问题:
您需要一个函数按字符串的字符对字符串进行排序(bccabc
-> abbccc
),以便将给定的字符串与现有的字符串进行比较。
Function<String,String> sortChars = s -> s.chars()
.sorted()
.mapToObj(i -> (char) i)
.map(String::valueOf)
.collect(Collectors.joining());
您可以预先计算一组唯一的令牌(数组中的值,已排序的字符),而不用在比较它们时对它们进行排序。
Set<String> tokens = Arrays.stream(arr)
.map(sortChars)
.collect(Collectors.toSet());
这将产生值"abc","acd","ack","dns"
。
此后,您可以创建一个函数,该函数检查给定的字符串,当按字符排序时,与任何给定的令牌匹配:
Predicate<String> match = s -> tokens.contains(sortChars.apply(s));
现在,您可以轻松地检查任何给定的字符串,如下所示:
boolean matches = match.test("bca");
匹配仅需要对给定的输入进行排序,并进行哈希集查找以检查其是否匹配,因此它非常有效。
您当然可以将Function和Predicate编写为方法({String sortChars(String s)
和boolean matches(String s)
,如果您不熟悉函数式编程。
方法1:将为O(NlogN)
方法2:将为O(N * M),其中M是数组中每个字符串的长度。
您应该在O(N)中进行线性搜索:
for (String str : arr) {
if (str.equals(target)) return true;
}
return false;
,
更多关于其他答案的附录。当然,您的两个选项具有不同的性能特征。但是:了解性能不一定是做出决定的唯一因素!
含义:如果您要说的是每分钟在大型数据集上运行数百或数千次时间的搜索:那么可以肯定的是,您应该花费大量时间来提出能够提供最佳性能的解决方案。最有可能的是,这包括在处理实际数据时使用 actual 测量进行各种实验。时间复杂度是一种理论构造,在现实世界中,还存在诸如CPU缓存大小,线程问题,IO瓶颈之类的要素,这些要素可能会对 real 数值产生重大影响。
但是:当您的代码仅每分钟执行一次工作,甚至处理几十或数百MB数据时...那么不值得关注性能。
>换句话说:“ sort”解决方案听起来很直接。它易于理解,易于实现,并且困难容易出错(带有一些不错的测试用例)。如果该解决方案“足够好”地完成了工作,那么请考虑使用该解决方案:简单的解决方案。
性能是一个奢侈品问题。仅在有理由的情况下解决。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。