不同的Summands问题贪婪算法

时间:2019-02-09 16:30:49

标签: java algorithm greedy

我尝试用贪婪算法解决“不同求和”问题

问题描述

任务。这个问题的目的是将给定的正整数表示为成对的和 尽可能使用不同的正整数。也就是说,找到最大值使得可以写成 1 + 2 + · · · + ,其中1, . . . , 是正整数,所有 ̸= 的{​​{1}}

输入格式。输入由单个整数组成。 约束条件。 1 ≤ < ≤ .

输出格式。在第一行中,输出最大数量1 ≤ ≤ 10^9,以使可以表示为总和 的成对截然不同的正整数。在第二行中,输出对成对的不同正整数 总计为(如果有很多这样的表示,请输出其中任何一种)。

我的代码:

如果输入太大,我的代码将失败,大约需要3.24秒,并且最大可用时间为1.5秒。

4 个答案:

答案 0 :(得分:1)

在ArrayList(summands变量)上​​执行contains时,它将遍历列表中的所有值以查找该项目是否已经存在。 O(n)操作。

尝试使用HashSet而不是列表,以获得更好的性能O(1)。

如果您关心结果(求和)中项目的顺序,则可以使用LinkedHashSet。

答案 1 :(得分:1)

至少有 k 个不同的求和项可以生成的最小数字就是从 1 k 的所有数字的总和。小于此数字的任何个数将最多使 k-1

Gauss具有一个公式,用于计算从 1 k 的数字之和。只是 k(k + 1)/ 2

您只需要找到最大的 k ,以使 k(k + 1)/ 2 <= n 。从上面可以知道,如果 k 更大,则无法将 n 划分为这么多求和数,因此这是最大的答案。

实际生成加到 n k 个求和也很容易-这只是从 1 到< strong> k-1 ,然后剩下的值( n-k(k-1)/ 2 )。

您可以直接求解 k

k(k + 1)/ 2 <= n

k²+ k-2n <= 0

k <=(sqrt(8n + 1)-1)/ 2

最后一步是通过二次公式。由于您想要最大的 k ,所以就

k = floor((sqrt(8n + 1)-1)/ 2)

答案 2 :(得分:0)

即使我们可以使用HashSet来解决它,但也可以不用它。

我们知道summands具有从1start的连续数字。因此,请注意,如果不是newNumber-start <= start,则必须停止操作,而不是检查列表。因此,newNumber应该是我们答案的最后一个数字。

通过最小化更改相应地修改代码,

...
        while (true) {
            if (newNumber-start <= start) { // possibly (newNumber <= start*2)
                summands.add(newNumber);
                newNumber = 0;
            } else {
...

现在整体时间复杂度为O(n^0.5)。 (搜索是O(n) = O(n^0.5 * n^0.5),搜索List

答案 3 :(得分:0)

在测试我的代码之后,我发现问题不仅在于代码性能,还在于代码有错误,但是使用HashSet确实很棒,它比ArrayList匹配的速度更快,这是我的新代码

我的代码

private static HashSet<Integer> optimalSummands(int n) {
    HashSet<Integer> summands = new HashSet<>();
    int start = 1;
    int newNumber = n;
    if (n == 2) {
        summands.add(2);
        return summands;
    }

    while (true) {
        if (newNumber < 0) {
            Object[] value = summands.toArray();
            int secondlast = (int) value[summands.size() - 2];
            int last = (int) value[summands.size() - 1];

            summands.remove(last);
            summands.remove(secondlast);

            newNumber = secondlast + last -1;

        }
        if (summands.contains(newNumber - start) ) {
            start++;
            continue;
        } else {
            newNumber -= start;
            summands.add(start);
            start++;

        }

        if (newNumber == 0) {
            return summands;
        }
    }
}