什么';s Java Stream distinct()的时间复杂度。Sorded()?
每次我接受编码面试时,我总是避免使用Java流,因为我不能很好地分析时间复杂性 例如:在我的日常工作中,我可能会这样写:什么';s Java Stream distinct()的时间复杂度。Sorded()?,java,java-stream,Java,Java Stream,每次我接受编码面试时,我总是避免使用Java流,因为我不能很好地分析时间复杂性 例如:在我的日常工作中,我可能会这样写: Arrays.stream(a).distinct().sorted().toArray(); 获取唯一编号并对其进行排序 但我很好奇时间的复杂性会是。。?是distinct()。排序后将成为嵌套循环吗 我需要把它们分开吗 int[] arr = Arrays.stream(a).distinct().toArray(); Arrays.stream(arr).sorted
Arrays.stream(a).distinct().sorted().toArray();
获取唯一编号并对其进行排序
但我很好奇时间的复杂性会是。。?是distinct()。排序后将成为嵌套循环吗
我需要把它们分开吗
int[] arr = Arrays.stream(a).distinct().toArray();
Arrays.stream(arr).sorted().toArray();
所以有时候当我面试的时候,我会用set来区分,然后对它们进行排序。。。。
但我真的想写一个干净的代码
如果有人能帮忙的话!谢谢大家! 没有明确的语句是可能的,因为您是根据接口开发的,并且规范没有规定特定的排序算法 对于泛型
流
,我们必须假设一个比较排序,它是任何算法都无法避免的
但是您的示例使用了一个IntStream
,原则上,它可以使用一个或类似的函数,具有O(n)。这在参考实现的实践中不会发生,因为在实践中,具有更好的最坏情况时间复杂度并不一定会导致更好的性能,并且元素的最大数量仅限于JVM的最大数组大小
distinct()
的时间复杂度为O(n),因为它只是检查添加到HashSet
中是否成功。将O(n)与O(n logn)相结合会导致O(n logn)的总体复杂性。也许面试官把时间的复杂性组合错了
但这是一个很好的例子,说明时间复杂度并不等于性能。当您使用sorted().distinct()
时,distinct()
操作将删除传入元素,这使得无需在幕后构建HashSet
。由于引用实现没有原始值集,因此消除了大量装箱开销。另一方面,使用distinct().sorted()
可以减少要排序的元素的数量,但它需要比流元素总数少得多的独特元素才能获得回报
这种性能差异不包括在时间复杂度中,这两种方法的时间复杂度仍然相同。但是如前所述,对于原始类型的流,可以使用具有不同时间复杂度的不同算法
但有一件事我们可以肯定。当您将操作拆分为两个流操作时,例如从第一个流操作请求一个结果数组并再次将其传递给Arrays.stream
,则底层实现不可能在下一个操作中利用有关上一个操作的知识
请注意,上面的语句假设一个终端操作,如您的示例的toArray
,它消耗所有元素,并需要维护生成的遭遇顺序。对于其他短路或无序终端操作,总体时间复杂度可能会发生变化,例如,sorted()。findFirst()
可以优化到与min()
等效的程度,或者对于无序终端操作(如sum()
)可以消除排序步骤。在当前的参考实现中不会发生这种情况,但是,正如前面所说的,您正在针对一个接口进行编程
对于基本流,这只适用于Java 9+。如前所述,
distinct()
没有原语专门化,它的实现方式类似于boxed().distinct().mapToInt(i->i)
,而在Java 8中,boxed()
被实现为mapToObj(Integer::valueOf)
,它会丢失有关排序输入的信息,正如。的最后一节中所解释的,没有明确的语句,因为您是根据接口开发的,并且规范没有强制要求特定的排序算法
对于泛型流
,我们必须假设一个比较排序,它是任何算法都无法避免的
但是您的示例使用了一个IntStream
,原则上,它可以使用一个或类似的函数,具有O(n)。这在参考实现的实践中不会发生,因为在实践中,具有更好的最坏情况时间复杂度并不一定会导致更好的性能,并且元素的最大数量仅限于JVM的最大数组大小
distinct()
的时间复杂度为O(n),因为它只是检查添加到HashSet
中是否成功。将O(n)与O(n logn)相结合会导致O(n logn)的总体复杂性。也许面试官把时间的复杂性组合错了
但这是一个很好的例子,说明时间复杂度并不等于性能。当您使用sorted().distinct()
时,distinct()
操作将删除传入元素,这使得无需在幕后构建HashSet
。由于引用实现没有原始值集,因此消除了大量装箱开销。另一方面,使用distinct().sorted()
可以减少要排序的元素的数量,但它需要比流元素总数少得多的独特元素才能获得回报
这种性能差异不包括在时间复杂度中,这两种方法的时间复杂度仍然相同。但是如前所述,对于原始类型的流,可以使用具有不同时间复杂度的不同算法
但有一件事我们可以肯定。当您将操作拆分为两个流操作时,例如从第一个流操作请求一个结果数组并再次将其传递给Arrays.stream
,则底层实现不可能在下一个操作中利用有关上一个操作的知识
请注意,上面的语句假设一个终端操作,就像您的示例的toArray
那样