【问题标题】:Nested For loop performance optimization in JAVAJAVA中的嵌套For循环性能优化
【发布时间】:2021-06-25 11:38:06
【问题描述】:

我正在为一份工作申请在 HackerRank 上做一些编码挑战,虽然我能够成功完成所有逻辑,但我在性能方面总是落后。大多数时候它与嵌套的 for 循环有关(我假设)。这将在 O(n^2) 时间内运行,但我假设挑战要求我比这更快地完成它。

谁能建议如何提高性能?下面是我制作的示例代码。它通过了逻辑测试用例,但性能超时失败。

 public static long maxValue(int n, List<List<Integer>> rounds) {
    
    int[] investments = new int[n+1];
    
    for (int i = 0; i < rounds.size(); i++) {
        List<Integer> newList = rounds.get(i);
        for(int k = newList.get(0); k <= newList.get(1); k++) {
            System.out.println(k);
            investments[k] += newList.get(2);
        }
    }        
    
    int maxInt = Arrays.stream(investments).max().getAsInt();
    
    return maxInt;

}

我有点犹豫发布代码应该做什么,因为害怕人们认为这是家庭作业,但问题是:

【问题讨论】:

  • 你错过了代码应该做什么?
  • 出于性能目的,尝试使用字典 O(1) 而不是列表 O(n),因为在迭代过程中一个比另一个花费更多的时间。
  • @HarrisMinhas 我无法更改参数
  • 唯一可以做的事情是,如果您对正在定义的新变量投资使用哈希集而不是列表。根据 mkyong.com/java/…>,for 循环是迭代中最快的
  • @HarrisMinhas 的建议与这个问题无关。他们认为无能为力的结论是不正确的。我现在正在制定一个正确的答案。

标签: java performance for-loop


【解决方案1】:

当做这样的问题时,“简单的方法”(在这种情况下,显然是创建一个 int 数组,使得每个投资都是数组中的一个“槽”,然后只写一些非常基本的循环)是很少是正确的方法,但正确的方法通常 [A] 更复杂,因为代码更多且更难遵循,并且 [B] 需要一个小的“技巧”库,从动态编程到许多晦涩的数学定理,依靠它甚至知道该怎么做。

关于如何获得这个武器库没有简单的答案。多读书,多学,做这样的练习几年。这就像成为世界知名的桌子工匠:您只需制作大量桌子,这里没有捷径。

不过,有两个“简单”的半解决方案(不是那么容易,但比花几年成为这方面的专家要容易):

  • 如果您对基础信息学和 NP-hard 有所了解,这会有所帮助:如果您觉得您设想的算法也可用于解决 NP-hard 问题,猜猜怎么着?停止。这是错误的——它会太慢。即,如果它与旅行推销员、背包等“一样快”,那么这是不正确的。这在分析问题本身时也很有帮助:这些练习中的很多听起来像是 8 个众所周知的 NP 难题之一,只是用不同的故事重述了它。这意味着您正在寻找使它不太像其中之一的关键因素,因为 NP-hard 集太慢了。故事的任何部分与您要比较的 NP 难题不完全匹配?这是以高效方式解决问题的关键。

  • 始终非常仔细地查看规定的限制,您似乎忘记在粘贴中包含这些限制。有时极限会给出方向,而了解它们以了解哪种算法是正确答案通常至关重要。

以此为背景,我必须知道在黑暗中疯狂地刺伤并猜测“限制”是这样的:

起始索引s 和结束索引e 等于1 &lt;= s &lt; e &lt;= 2000000000(即20 亿)。轮数n:1 &lt;= n &lt;= 100000,最后保证总投入为正数,答案永远不会超过20亿。

如果一个问题不包含这样的限制,我敢打赌,你正在使用的材料设计得很糟糕。寻找其他材料。如果不知道这些限制或需要猜测,绝大多数这样的谜题是无法解决的,而且你肯定不想玩赢家幸运的游戏。你想玩一个游戏,赢家是最有技巧的人。

如果限制如我所述,那么想象以下输入数据集:

amount start end
10     1     1000000000
10     1     1000000000
10     1     1000000000
10     1     1000000000
10     1     1000000000

您的算法将循环 60 亿次以确定正确答案。当然,现在想想,你已经意识到,有了这样的输入,一个循环更多大约 6 次(字面上的速度增加十亿)的算法也是可能的。

问题就在于此。一旦你把它分解成单一的投资,你就已经输了。相反,您希望接受这些范围。

有自定义数据类型,例如让您使用范围的番石榴。您也可以自己编写此代码。

一个简单的算法是拥有一个将不相交范围映射到正确总和的数据结构。因此,如果输入是:

amount start end
10     1     1000
20     1     500
30     1     1000

然后在处理第一轮之后,您的数据结构仅包含 1 个条目而不是 1000 个条目。那一项是:

1-1000    10

在处理第二个输入的过程中,您意识到必须将其拆分。您最终得到 2 个条目(不是 1000 个):

1-500     30
501-1000  10

第三个之后:

1-500     60
501-1000  40

您还可以在运行时跟踪最大值(只需在每次向任何内容添加任何内容时更新“最大值” - 最后不需要循环,但我怀疑这就是您的算法在这里被认为太慢的原因。那个对所有数据结构的最终循环不会改变您的 O(n) 评级)。

IF(如果很大!)输入范围使得开始/结束索引可能非常大,这将是一种可能会通过性能限制的算法。

范围重叠的策略更加复杂;这涉及首先对您的输入进行排序。如果输入大小可能非常大(大量回合)并且开始/索引限制受到限制,则这更有可能是正确的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-27
    • 2020-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-28
    相关资源
    最近更新 更多