包含自然数的最长子序列的长度

时间:2015-01-31 11:24:32

标签: algorithm

从给定的数组中,我想找到最长的连续子序列的长度L,该子序列包含任意顺序从1到L的自然数。

示例:

数组[11] = {8,3,2,4,5,1,3,1,2,3,1}

满足上述条件的子序列是:

1 2 3:= L = 3

2 3 1:= L = 3

2 4 5 1 3:= L = 5(:=最大)

因此要求的答案= 5

我的解决方案:

我只能想到O(N ^ 3)时间复杂度的基本方法。根据我的方法,我会考虑每对,并检查这些对中每个元素的重复次数是否为零,最小元素= 1,最大元素= L.我会每次更新长度。

但是这个解决方案根本不可行,因为数组N的长度可以达到10 ^ 5并且数组元素<= N.所以我要求一个在1秒内运行的有效方法。

坦率地说,这是SPOJ的一个问题,我正在努力优化但不能。希望得到帮助。

2 个答案:

答案 0 :(得分:1)

稍微好于O(n^3) - O(n^2*logn)

对于每个可能的开始,您可以尝试O(n * logn)中的所有子序列。只需逐步构建一组值并检查它是否为1..L

int best=std::numeric_limits<int>::max();
for(int start=0;start<N;++start)//O(N)
{
    std::set<int> distinctValues;
    for(int c=start;c<N;++c)//O(N)
    {
        distinctValues.insert(array[c]);//O(log N)
        if(minimalValue(distinctValues)==1
          && maximalValue(distinctValues)==distinctValues.size()
          && distinctValues.size()==c-start+1//to ensure that we had no duplicates
          && distinctValues.size()>best)
            best=distinctValues.size();
    }
}

答案 1 :(得分:0)

我会在保留原始索引的同时对数字进行排序 - O(n*logn),如下所示:

[(1, (5,7,10)),
 (2, (2,8)),
 (3, (1,6,9)),
 (4, (3)),
 (5, (4)),
 (8, (0))]

然后找到L的候选者(在这种情况下从1开始连续的最大数字,5)并尝试构建所有候选的位置子序列,但只保留那些间隙总和的子序列是&lt; = step-1,例如以下步骤:

5: [[4]]
4: [[3,4]]   # gap(3,4) = 0
3: [[1,3,4], # gap(1,3) + gap(3,4) = 1 + 0
    [3,4,6], # gap(3,4) + gap(4,6) = 0 + 1
    [3,4,9]] # gap(3,4) + gap(4,9) = 0 + 4 => reject as 4 > 3-1
2: [[1,2,3,4], # gaps = 0
    [1,3,4,8], # gaps = 1+0+3 > 1 => reject
    [2,3,4,6], # gaps = 1
    [3,4,6,8]] # gaps = 0+1+1 > 1 => reject
1: [[1,2,3,4,5],
    [1,2,3,4,7],
    [1,2,3,4,10],
    [2,3,4,5,6],
    [2,3,4,6,7],
    [2,3,4,6,10]]

因此L=5有2个有效序列。如果未找到,则可以设置L=4并重复..

或者也许可以使用1启动步骤,并为每个序列分配最小可行L,但我不确定如何在此方案中拒绝不合适的序列...

如果没有拒绝序列,最坏的情况是O(√n ^ √n)这是非常糟糕的,但鉴于拒绝限制,实际复杂性会低得多,但我不知道如何计算它恰好...

这可能不是最好的解决方案,但我希望它会让你思考:)