使用fenwick树或BIT的数组中非减少子序列的最大总和

时间:2013-03-04 02:05:52

标签: arrays algorithm data-structures fenwick-tree

如何使用fenwick树找到数组中非递减子序列的最大总和?例如,我们有1 4 4 2 2 3 3 1,这里非减少子序列的最大总和是11(1 2 2 3 3)。

1 个答案:

答案 0 :(得分:1)

可以使用动态编程算法找到最大总和。扫描数组,并为每个元素将其值添加到有效的最大子序列总和(子序列以不大于此元素的值结束)。

有效实施需要一些方法来快速找到给定子范围内的最大值。可以使用增强二进制搜索树来完成它。 Fenwick树只是增强二叉搜索树的有效实现。 Fenwick树的最常见用途是在某个子范围内找到值的总和。微不足道的修改允许使用它来查找子范围最大值(这是有效的,因为在这种特殊情况下,Fenwick树中的值永远不会减少)。

有关详细信息,请参阅此Python代码:

array = [1, 4, 4, 2, 2, 3, 3, 1]

numbers = sorted(set(array))
n = len(numbers)
indexes = {numbers[v]:v+1 for v in range(0, n)}
n += 1
bit = [0] * n
result = 0

for x in array:
    pos = indexes[x]
    i = pos
    maximum = 0
    while i != 0:
        maximum = max(maximum, bit[i])
        i = i & (i-1)
    x += maximum
    i = pos
    while i < n:
        bit[i] = max(bit[i], x)
        i += i & -i
    result = max(result, x)

print(result)

indexes字典用于将Fenwick树的大小从输入数组中的最大数字减少到数组的大小。第一个嵌套while在Fenwick树中查找子范围最大值。第二个嵌套while在其中一个总和更新后更新Fenwick树。

此代码仅适用于正数数组。一般情况下,应通过过滤掉所有非正数来预处理输入数组。

时间复杂度为O(N log N)。空间复杂度为O(N)。