【问题标题】:How to find the difference of all consecutive sub-sequences?如何找到所有连续子序列的差异?
【发布时间】:2018-10-27 09:26:25
【问题描述】:

我需要一个有效的算法,它可以找到所有连续子序列的差之和,但我不知道该怎么做。

例如,12345的所有连续子序列:

12    (Dif = 1)
23    (Dif = 1)
34    (Dif = 1)
45    (Dif = 1)
123   (Dif = 2)
234   (Dif = 2)
345   (Dif = 2)
1234  (Dif = 3)
2345  (Dif = 3)
12345 (Dif = 4)

Sum of the difference = 20

序列元素的计数 >= 2

每个元素 >= 1

时间限制:1s。

我写了代码,但是太慢了:

#include <bits/stdc++.h>

using namespace std;

int main() {
    cin.tie(0);
    iostream::sync_with_stdio(false);

    int count;
    cin >> count;

    int elem;

    vector<int> vec;
    int sum = 0;

    for (int i = 0; i < count; i++) {
        cin >> elem;

        if (vec.size() > 0) {
            sum += abs(vec.back() - elem);
        }

        vec.push_back(elem);
        if (vec.size() > 2) {
            sum += abs(*max_element(vec.begin(), vec.end()) -             *min_element(vec.begin(), vec.end()));
        }

        for (int z = 3; z < count; z++) {
            if (vec.size() > z) {
                sum += abs(*max_element(vec.begin() + i - z + 1, vec.end()) - *min_element(vec.begin() + i - z + 1, vec.end()));
            }
        }
    }

    cout << sum;

    return 0;
}

我发现子序列的计数可以通过三角形数公式(其中n - 序列长度)找到:

count = 1/2 * n * (n - 1);

对于 n = 300000,子序列的计数为 450 亿。

如何更快地做到这一点?我需要算法。

【问题讨论】:

  • 如果你想改进已经工作的代码,最好在SE Code Review询问。

标签: c++ dynamic-programming


【解决方案1】:

我的第一个想法是构建一棵树以记住子答案(即动态编程)并将答案组合在一起。但是,每个更高的分支严格来说并不是它下面的节点的总和。考虑例如:

然而,我注意到节点是可预测的。即:

当扩展到 6 个连续节点时:

概括地说是

SUM( i * (n - i) )i = [1 .. n) 其中n &gt;=2

这当然是在 O(N) 时间内运行,除了加 + 乘之外不需要任何其他东西。


然而,让我感到困扰的是,也许这个求和公式可以简化为一个简单的方程。所以我查了properties of summation formulas 并努力得到一个简单的方程式:

这意味着(n^3 - n) / 6 应该在 O(1) 时间内执行。我测试了前 6 个,它给出了正确的答案...

【讨论】:

    猜你喜欢
    • 2021-04-25
    • 1970-01-01
    • 1970-01-01
    • 2015-02-03
    • 2017-06-22
    • 2015-08-22
    • 2015-11-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多