2014-10-09 83 views
0

在给定数组中查找带有不同数字的最大连续子数组和。如果在任何子阵列中存在至少两个相等的数字,则该数字的值等于0.查找不同数字的最大连续子数组求和

所有数字都是正数。

我写了O(n²)蛮力算法,但它肯定太慢了。 我试图用Kadane的算法来混合它,但似乎并不奏效。

+0

你试过对数组进行排序并插入所有不同的数字吗? O(n * log(n))用于排序+ O(n)用于插入 – CIsForCookies 2014-10-09 18:41:35

+0

@CIsForCoocckies它是不正确的。对于数组5,2,2,4来说,选择整个数组是最理想的,尽管并非所有的数字都是不同的。 – kraskevich 2014-10-09 18:43:00

+0

我想我不明白这个问题。如果subArray是5,2,2,4,它的总和是(5 + 4 = 9),而不是取(5,4,2)总和为11,那么为什么要整个数组呢? – CIsForCookies 2014-10-09 18:48:34

回答

1

使用分段树可以获得时间复杂度O(n log n)

  1. 让我们假设答案的左边框(我们称之为L)是固定的。从左边的所有东西都可以忽略。数组其余部分的每个元素可以表示为:
    a)+x如果它是第一次出现x
    b)-x如果它是第二次出现x
    c)0如果它是第三次(或更晚)发生的x,
    其中x = a[i]
    然后答案是所有子阵列的最大子阵列总数[L, R]其中R >= L

  2. 那么如何有效实施?最初,为[0, n - 1]范围构建分段树。段树中的每个叶子都包含前缀总和,该总和始于L,并以此叶子结尾(到目前为止为0)。填写它为L = 0(通过遍历整个阵列,并添加+x-x适当的足够的分段树)。这些部分在O(n log n)中工作。还有一种观察:当L增加时,该值仅在最多3个位置上变化(因为a[L]的第一次出现现在处于另一个位置,但其他数字没有变化)。分段树中的每个更新为O(log n),因此需要O(log n)时间来增加L一次。总时间复杂度为O(n log n),因为L递增O(n)次。不要忘记查询分段树,以获得每个L的最大值,并选择最大的值作为答案。

因此,所有你需要的是一个支持两种操作的段树:添加相同数量的所有元素在给定的范围内,并得到所有元素中最高。这是一个众所周知的问题,并不是很难实施。

+0

嗯,我想你是对的!但我仍然不明白我应该如何增加L,你能解释我吗?谢谢! – 2014-10-09 19:45:40

+0

我们来看看数字a [L]。当L递增时,它的第一个和第二个位置向右移动。所以+α[L]和-a [L]现在位于其他位置和段树应appropriatly更新(如果您存储给定数字的位置,你可以找到新的位置快速使用二进制搜索或通过移动指针当你移动L)。 – kraskevich 2014-10-09 19:50:06