从给定的数组中,我想找到最长的连续子序列的长度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的一个问题,我正在努力优化但不能。希望得到帮助。答案 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)
这是非常糟糕的,但鉴于拒绝限制,实际复杂性会低得多,但我不知道如何计算它恰好...
这可能不是最好的解决方案,但我希望它会让你思考:)