【问题标题】:Reducing time complexity of an algorithm降低算法的时间复杂度
【发布时间】:2015-08-03 10:56:29
【问题描述】:

这是一项来自代码的任务,需要 O(n) 复杂度。虽然我已经解决了它给出正确结果的任务,但时间复杂度是 O(n*n)。在解释如何将复杂性降低到 O(n) 时,我们将不胜感激。

任务描述:

给出了一个由 N 个整数组成的非空零索引数组 A。 数组 A 代表磁带上的数字。

任何整数 P,例如 0

两部分的区别在于:|(A[0] + A[1] + ... + A[P - 1]) - (A[P] + A[P + 1] + ... + A[N - 1])|

换句话说,它是总和之间的绝对差 第一部分和第二部分的总和。

例如,考虑数组 A,这样:

A[0] = 3 A[1] = 1 A[2] = 2 A[3] = 4 A[4] = 3

我们可以把这个磁带分成四个地方:

    P = 1, difference = |3 − 10| = 7
    P = 2, difference = |4 − 9| = 5
    P = 3, difference = |6 − 7| = 1
    P = 4, difference = |10 − 3| = 7

写一个函数:

int solution(vector<int> &A);

给定一个由 N 个整数组成的非空零索引数组 A,返回 可以达到的最小差异。

例如,给定:

A[0] = 3 A[1] = 1 A[2] = 2 A[3] = 4 A[4] = 3

该函数应返回 1,如上所述。

假设:

    N is an integer within the range [2..100,000];
    each element of array A is an integer within the range [−1,000..1,000].

复杂性:

    expected worst-case time complexity is O(N);
    expected worst-case space complexity is O(N), beyond input storage (not counting the storage required for input arguments).

输入数组的元素可以修改。

My solution:  
int solution(vector<int>& A)
{
    // write your code in C++11
    int result = std::numeric_limits<int>::max();
    int part_1 = 0;
    int part_2 = 0;
    for (auto beg = A.cbegin(), end = A.cend(); beg != prev(end); ++beg)
    { 
        part_1 = accumulate(A.cbegin(),beg + 1,0);
        part_2 = accumulate(beg + 1,end,0);
        int current_result = abs(part_1 - part_2);
        if (current_result < result)
        {
            result = current_result;
        }

    }

    return result;
}

【问题讨论】:

  • 我认为任务中有一个小错误 - 它说“0

标签: c++ algorithm


【解决方案1】:

让S[i] = sum of the first i elements。您可以使用单个 for 循环来计算:

S[0] = A[0]
for (int i = 1; i < n; ++i)
  S[i] = S[i - 1] + A[i]

然后,对于每个索引0 &lt; i &lt; n,直到i - 1 的总和就是S[i - 1]。从i 到数组末尾的总和是S[n - 1] - S[i - 1]:

S[n - 1] = A[0] + ... + A[n - 1]
S[i - 1] = A[0] + ... + A[i - 1]

0 < i < n

S[n - 1] - S[i - 1] =  A[0] + ... + A[i - 1] + A[i] + ... + A[n - 1] -
                      (A[0] + ... + A[i - 1])
                    = A[i] + ... + A[n - 1]

在计算S 之后,运行另一个循环并检查两个和之间的差异,就像我描述的那样,在 O(1) 中计算:

for (int i = 1; i < n; ++i)
{
  sum_left = S[i - 1]
  sum_right = S[n - 1] - S[i - 1]

  // see if |sum_left - sum_right| is better than what you have so far
}

时间复杂度为 O(n),因为您只运行两个 for 循环,在其中每次迭代只执行 O(1) 操作。内存复杂度为O(n),因为您必须存储S,它与您的输入大小相同。

根据我们可以做出的假设,将S 声明为int[n] 应该没问题。

【讨论】:

  • 通过将sum_left 和sumright 更新为+=/-= A[i](而不是使用S),可以将内存复杂度降低到O(1)。
  • @IVlad,您好,感谢您的回答。关于i个元素之和的计算,用std::accumulate来做不是更好吗?
  • @Thereisnothingwecando 在我的原始解决方案中,您需要访问所有部分总和。 std::accumulate 返回一个总和,但您需要访问每个 i 的第一个 i 元素的总和。或者您可以使用std:accumulate 计算整个数组的总和,然后使用@Jarod42 的优化来使用O(1) 内存。
  • @IVlad 另一件事是他们特别说使用 c++11,而您提出的充其量是 C++98。你会如何解决这个问题?
  • @Thereisnothingwecando C 是 C++11 的子集,所以没有问题。我建议只使用基本的语言元素:for 循环、int 变量和数组。如果必须使用 C++ 元素,可以使用 std::vector 代替数组。除此之外,还有std::accumulate 的最佳解决方案,真的没有什么可做的了。
猜你喜欢
  • 2014-04-21
  • 1970-01-01
  • 2011-06-15
  • 2021-03-30
  • 1970-01-01
  • 2023-03-06
  • 2012-07-28
  • 2016-10-07
相关资源
最近更新 更多