连续序列的总和

时间:2015-02-28 08:44:43

标签: algorithm

给定一个包含N个元素的数组A,我想在A的所有可能的连续子序列中找到最小元素的总和。我知道如果N很小,我们可以寻找所有可能的子序列,但是当N到达时10 ^ 5什么是最好的方法来找到这笔钱?

示例:令N = 3且A [1,2,3]则ans为10作为可能的连续子序列{(1),(2),(3),(1,2),(1,2) ,3),(2,3)}所以最小元素之和= 1 + 2 + 3 + 1 + 1 + 2 = 10

2 个答案:

答案 0 :(得分:5)

  • 让我们修复一个元素(a[i])。我们想要知道最右边元素的位置小于iL)左侧的位置。我们还需要知道最左边元素的位置小于位于iR)右侧的元素的位置。

  • 如果我们知道LR,我们应该在答案中添加(i - L) * (R - i) * a[i]

  • 可以使用堆栈在线性时间内为所有L预先计算Ri。伪代码:

    s = new Stack
    L = new int[n]
    fill(L, -1)
    for i <- 0 ... n - 1:
        while !s.isEmpty() && s.top().first > a[i]:
            s.pop()
        if !s.isEmpty():
            L[i] = s.top().second
        s.push(pair(a[i], i))
    

    我们可以反转数组并运行相同的算法来查找R

  • 如何处理相同的元素?我们假设a[i]是一对<a[i], i>。现在所有元素都是不同的。

时间复杂度为O(n)

这是一个完整的伪代码(我假设int可以在这里保存任何整数值,你应该这样做 选择一个可行的类型以避免实际代码中的溢出。我还假设所有元素都是不同的):

int[] getLeftSmallerElementPositions(int[] a):
    s = new Stack
    L = new int[n]
    fill(L, -1)
    for i <- 0 ... n - 1:
        while !s.isEmpty() && s.top().first > a[i]:
            s.pop()
        if !s.isEmpty():
            L[i] = s.top().second
        s.push(pair(a[i], i))
    return L

int[] getRightSmallerElementPositions(int[] a):
    R = getLeftSmallerElementPositions(reversed(a))
    for i <- 0 ... n - 1:
        R[i] = n - 1 - R[i]
    return reversed(R)

int findSum(int[] a):
    L = getLeftSmallerElementPositions(a)
    R = getRightSmallerElementPositions(a)
    int res = 0
    for i <- 0 ... n - 1:
        res += (i - L[i]) * (R[i] - i) * a[i]
    return res

答案 1 :(得分:-1)

如果列表已排序,您可以将大小为1,然后是2,然后是3的所有子集视为N.算法最初效率不高,但优化版本如下。这是一些伪代码。

let A = {1, 2, 3}
let total_sum = 0

for set_size <- 1 to N
    total_sum += sum(A[1:N-(set_size-1)])

首先,设置一个元素:{{1},{2},{3}}:对每个元素求和。

然后,两个元素{{1,2},{2,3}}的集合:对每个元素求和,但最后一个。

然后,三个元素{{1,2,3}}的集合:对每个元素求和,但最后两个元素。

但这种算法效率低下。为了优化到O(n),将每个第i个元素乘以N-i和sum(这里从零开始索引)。直觉是第一个元素是N个集合中的最小元素,第二个元素是N-1集合中的最小元素等。

我知道这不是一个python问题,但有时代码有帮助:

A = [1, 2, 3]

# This is [3, 2, 1]
scale = range(len(A), 0, -1) 

# Take the element-wise product of the vectors, and sum
sum(a*b for (a,b) in zip(A, scale))

# Or just use the dot product
np.dot(A, scale)