【问题标题】:Given million number in a list. How to mutiply each element by a constant with minimum time complexity给定列表中的百万个数字。如何以最小的时间复杂度将每个元素乘以一个常数
【发布时间】:2016-05-11 06:13:39
【问题描述】:

我编写了一个 java 程序,它将列表中的每个数字乘以一些常量。下面是程序。我创建了一个 myNewNumbers 列表来存储这些相乘的数字。以下是我的疑问

有没有更好的方法来以最小的时间复杂度写这个? 目前在我的 for 循环中有 10 个元素。如果用户想要为 100 万个元素执行此操作,如何处理? 我是多线程的初学者。我如何确保它在多线程中工作

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MultiplyHugeNumber {

    static List<Integer> mynumbers;
    static List<Integer> myNewnumbers;
    static Integer MUTIPLY_ELEMENT=2;

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        mynumbers= new ArrayList<Integer>();
        for (int i = 0; i < 10; i++) {
            mynumbers.add(i);
        }

        System.out.println(Arrays.toString(mynumbers.toArray()));
        myNewnumbers= new ArrayList<>();
        for (Integer mynumber : mynumbers) {
            myNewnumbers.add(mynumber*MUTIPLY_ELEMENT);

        }

        System.out.println(Arrays.toString(myNewnumbers.toArray()));
    }

 o/p:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

【问题讨论】:

  • 哦,看,过早的优化。我们生活在 2016 年,而不是 1980 年,您的计算机可以处理数百万次乘法运算。
  • 多线程与时间复杂度无关。无论是否使用多个线程,您都必须处理一次所有元素,因此您的时间复杂度将为O(n)。可能是您将它与并行处理混合以减少总执行时间。

标签: java multithreading arraylist


【解决方案1】:

如果您有一百万个元素,并且您需要将每个元素乘以一个常数,那么您将需要执行一百万次操作。没有办法解决它 - 它是 O(n)。

也就是说,创建列表可以是 O(1)(恒定时间),如果您对延迟评估列表没问题的话。 Guava 的 Lists.transform 就是这样做的:

List<Integer> myNumbers = ...
List<Integer> myNewNumbers = Lists.transform(myNumbers, i -> i * MULTIPLY_ELEMENT);

这不会减少执行所有乘法所需的总时间;事实上,总体而言,它可能需要更多时间,因为 JVM 更难优化。如果您多次访问同一个元素,它也会变慢,因为每次都会应用转换。也就是说,它不太可能会慢到您会注意到的程度。

这种方法还有一个限制,即您不能将新元素添加到转换后的列表中(如 JavaDocs 中所述)。但是,根据您的情况,快速创建初始列表可能还有其他好处。

【讨论】:

    【解决方案2】:

    (归功于@STaefi)将输入值列表乘以一个常数值的时间复杂度为O(n)。这种复杂性与多线程实现无关。

    您的程序:将一个数字列表乘以一个常数属于所谓的"Embarrassingly Parallel"问题类别:

    “[...] 只需很少或无需努力即可将问题分成多个并行任务 [...]”

    输入列表中的每一项都可以与常数相乘,而无需考虑任何其他输入项或全局状态。

    有多种方法可以并行化给定的任务。请注意,对于少量输入值或在此特定示例中根本不值得,设置线程的开销可能不值得。

    使用 Java 8 流的示例:

     mynumbers.parallelStream()
              .map(in -> in * MUTIPLY_ELEMENT)
              .collect(Collectors.toList());
    

    【讨论】:

      【解决方案3】:

      这是 100% 过早的优化,在这种情况下很可能没有值得进行的优化。

      但是..纯粹“从学术上讲”,您需要在这里问自己一个问题,即结果的顺序是否重要?

      如果没有,那么使用 Streams,这很简单,这是一个 100 个数字的示例:

          Integer MUTIPLY_ELEMENT = 2;
          List<Integer> resultNumbers = IntStream.range(0,100)
                  .parallel()
                  .map(i->i*MUTIPLY_ELEMENT)
                  .boxed()
                  .collect(Collectors.toList());
      

      如果您确实关心排序,但仍想获得并行处理的好处,您可以利用这样一个事实,即您的操作(乘以 2)足够简单,结果数字仍然是相同的相对值“自然”顺序,只需在map() 调用之后在流上调用sorted()。但是,排序操作可能会花费很长时间,就像您只是单线程一样。

      另外,请理解这绝不是“真实世界”的场景,您几乎永远不会遇到这样的实际问题。希望您只是想大致了解并行性,因为在您尝试过单线程模型并证明它不够充分之前,您永远不会真正想要进行这种类型的优化。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-05-23
        • 2016-05-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多