Algorithm 重叠序列

Algorithm 重叠序列,algorithm,sequence,time-series,Algorithm,Sequence,Time Series,有许多开始-结束对序列。如何找到包含在所有序列中的所有范围?起始和结束是整数,它们可能距离很远,所以生成序列的位字段和&-ing它们是不可行的。一行(即一个序列)上的范围(即开始-结束对)不重叠,如果有帮助的话。开始和结束有上下限,我认为32位整数就足够了(即,0它被称为。我可以用后缀树来解决。在这方面有一个非常干净的Java实现,它可以处理两个以上的源字符串 我不知道你是否在处理角色,但我相信如果你不这样做,你可能可以调整它。我认为你可以通过2乘2的序列融合来实现这一点 每个融合应在所考虑序列

有许多开始-结束对序列。如何找到包含在所有序列中的所有范围?起始和结束是整数,它们可能距离很远,所以生成序列的位字段和
&
-ing它们是不可行的。一行(即一个序列)上的范围(即开始-结束对)不重叠,如果有帮助的话。开始和结束有上下限,我认为32位整数就足够了(即,0它被称为。我可以用后缀树来解决。在这方面有一个非常干净的Java实现,它可以处理两个以上的源字符串


我不知道你是否在处理角色,但我相信如果你不这样做,你可能可以调整它。

我认为你可以通过2乘2的序列融合来实现这一点

每个融合应在所考虑序列中间隔数的线性时间内可行(如果序列已排序),并且需要M-1融合(具有M个序列)

以您的示例为例,添加一个额外的序列:

|----------|       |---------------------|           |----------|
     |----------------------|                      |-------|
                |---------------------|                 |--|
        |-----------------------------------|           |-----|  
按序列对进行熔断:

     |-----|       |--------|                        |-----|
                |---------------------|                 |--|
再次熔断:

                   |--------|                           |--|
但您可能会找到一种更快的方法,最坏的情况是O(N logm)运行时(N总间隔数)

编辑:用于融合的伪代码

Take s1 and s2 an iterator on each sequence
While there are still intervals in both sequences
    Compare the intervals:
    If s1.begin < s2.begin
        If s2.begin < s1.end
            If s2.end > s1.end
                Add [s2.begin,s1.end] to the fused sequence
                Increment s1
            Else
                Add [s2.begin,s2.end] to the fused sequence
                Increment s2
        Else
            Increment s1
    Else
        Same thing with s1 and s2 reversed
在每个序列上取s1和s2作为迭代器
虽然两个序列中仍有间隔
比较时间间隔:
如果s1.begins1.end
将[s2.开始,s1.结束]添加到融合序列中
增量s1
其他的
将[s2.开始,s2.结束]添加到融合序列中
增量s2
其他的
增量s1
其他的
s1和s2的情况也一样

假设每个序列中的范围不重叠,这应该不难。在这种情况下,只需在所有点上迭代,并在输入或离开范围时跟踪即可

将所有序列中的所有点放到一个列表中,对其进行排序,并记住每个点是起点还是终点

100 S ---
140 S  |   ---
200 E ---   |
280 S       |  ---
300 S ---   |   |
450 E  |   ---  |
580 E  |       ---
600 E ---
780 S      ---
800 S ---   |
820 S  |    |  ---
860 E  |   ---  |
860 E  |       ---
900 E ---
现在,在这个列表上迭代,每次遇到起点时,递增计数器,每次遇到终点时,递减计数器

      0
100 S 1
140 S 2
200 E 1
280 S 2  
300 S 3 <--
450 E 2 <--
580 E 1
600 E 0
780 S 1
800 S 2
820 S 3 <--
860 E 2 <--
860 E 1
900 E 0
点的类,带有区分起点和终点的标志

internal sealed class Point
{
    private readonly Int32 position = 0;

    private readonly Boolean isStartPoint = false;

    public Point(Int32 position, Boolean isStartPoint)
    {
        this.position = position;
        this.isStartPoint = isStartPoint;
    }

    internal Int32 Position
    {
        get { return this.position; }
    }

    internal Boolean IsStartPoint
    {
        get { return this.isStartPoint; }
    }
}
最后给出了算法和测试程序

internal static class Program
{
    private static void Main()
    {
        var s1 = new List<Range> { new Range(100, 200), new Range(300, 600), new Range(800, 900) };
        var s2 = new List<Range> { new Range(140, 450), new Range(780, 860) };
        var s3 = new List<Range> { new Range(280, 580), new Range(820, 860) };

        var sequences = new List<List<Range>> { s1, s2, s3 };

        var startPoints = sequences.SelectMany(sequence => sequence)
                                   .Select(range => new Point(range.Start, true));

        var endPoints   = sequences.SelectMany(sequence => sequence)
                                   .Select(range =>  new Point(range.End, false));

        var points = startPoints.Concat(endPoints).OrderBy(point => point.Position);

        var counter = 0;

        foreach (var point in points)
        {
            if (point.IsStartPoint)
            {
                counter++;

                if (counter == sequences.Count)
                {
                    Console.WriteLine("Start {0}", point.Position);
                }
            }
            else
            {
                if (counter == sequences.Count)
                {
                    Console.WriteLine("End   {0}", point.Position);
                    Console.WriteLine();
                }

                counter--;
            }
        }

        Console.ReadLine();
    }
}

您的示例与您描述的不匹配。您似乎想找到重叠序列最多的序列。我不理解最终结果,您能澄清一下吗?我很抱歉造成混淆,我的错。现在可以了吗?“一系列开始-结束对”看起来很困惑。这些是字符序列还是你说的像时间范围一样的范围?@AudriusMeškauskas:像时间范围。也许我误解了,但我不想要最长的公共范围,我想得到所有的范围。你知道这些是间隔-图形表示只是为了帮助我们可视化它。l最常见的子字符串可能会“捕获”空格,我明白了。那么,我认为LCS在这里没有帮助,因为我不想创建超出范围的“句子”,请参见上面的位字段注释。我怀疑是否有更快的方法来实现此目的..+1您在这里失去了我。“保险丝”是什么意思?查看图表是有意义的,但如何以编程方式实现fuse?利用两个列表都已排序的事实,您可以在每一步的第一个或第二个间隔列表上增加一个迭代器。我将编辑答案以使其更为明显。看起来不错,但它不是线性时间算法。更准确地说,它具有Drad最坏的情况。考虑一个“FoScess”不能消除任何间隔的情况。但是,我仍然可以很幸运,我必须考虑它。谢谢!优雅,和线性运行时(总的间隔数)与正确的结构。它只是<代码> O(n)。如果序列已经排序,否则对点进行排序显然会使其成为
O(n log n)
。实际上,我对排序案例的线性实现的想法不是线性的,而是O(NxM)-M个序列,但它可以在O(n log M)中完成。好吧,这对我来说完全是开箱即用的想法,非常感谢!你知道它与@Khaur的方法相比会有什么表现吗?我想这很大程度上取决于基础数据……Khaur的解决方案从理论上看比较慢。可能实现合并步骤比使用给定的伪代码更有效,但我是可以肯定的是,不可能获得与我的解决方案相同的运行时间。从实际的角度来看,可能没有相关的性能差异,只要您只需要处理几十个或几百个范围。
      0
100 S 1
140 S 2
200 E 1
280 S 2  
300 S 3 <--
450 E 2 <--
580 E 1
600 E 0
780 S 1
800 S 2
820 S 3 <--
860 E 2 <--
860 E 1
900 E 0
internal sealed class Range
{
    private readonly Int32 start = 0;

    private readonly Int32 end = 0;

    public Range(Int32 start, Int32 end)
    {
        this.start = start;
        this.end = end;
    }

    internal Int32 Start
    {
        get { return this.start; }
    }

    internal Int32 End
    {
        get { return this.end; }
    }
}
internal sealed class Point
{
    private readonly Int32 position = 0;

    private readonly Boolean isStartPoint = false;

    public Point(Int32 position, Boolean isStartPoint)
    {
        this.position = position;
        this.isStartPoint = isStartPoint;
    }

    internal Int32 Position
    {
        get { return this.position; }
    }

    internal Boolean IsStartPoint
    {
        get { return this.isStartPoint; }
    }
}
internal static class Program
{
    private static void Main()
    {
        var s1 = new List<Range> { new Range(100, 200), new Range(300, 600), new Range(800, 900) };
        var s2 = new List<Range> { new Range(140, 450), new Range(780, 860) };
        var s3 = new List<Range> { new Range(280, 580), new Range(820, 860) };

        var sequences = new List<List<Range>> { s1, s2, s3 };

        var startPoints = sequences.SelectMany(sequence => sequence)
                                   .Select(range => new Point(range.Start, true));

        var endPoints   = sequences.SelectMany(sequence => sequence)
                                   .Select(range =>  new Point(range.End, false));

        var points = startPoints.Concat(endPoints).OrderBy(point => point.Position);

        var counter = 0;

        foreach (var point in points)
        {
            if (point.IsStartPoint)
            {
                counter++;

                if (counter == sequences.Count)
                {
                    Console.WriteLine("Start {0}", point.Position);
                }
            }
            else
            {
                if (counter == sequences.Count)
                {
                    Console.WriteLine("End   {0}", point.Position);
                    Console.WriteLine();
                }

                counter--;
            }
        }

        Console.ReadLine();
    }
}
Start 300
End   450

Start 820
End   860