Arrays 计算连续时间内发生次数的算法

Arrays 计算连续时间内发生次数的算法,arrays,algorithm,perl,sorting,count,Arrays,Algorithm,Perl,Sorting,Count,我有一组数据,告诉我组件的开/关状态随时间的变化。数据如下所示: 0 1 120 1 240 0 360 0 480 1 600 1 720 1 840 0 960 0 1080 0 1200 1 1320 1 1440 0 1560 0 1680 1 1800 0 1920 1 第一列以秒为单位显示时间,第二列显示状态(1为开,0为关) 我需要知道最多1秒的600秒是多少。例如,0-600有3*120秒,所以组件处于打开状态时为360秒。但120-720

我有一组数据,告诉我组件的开/关状态随时间的变化。数据如下所示:

0    1
120  1
240  0
360  0
480  1
600  1
720  1
840  0
960  0
1080  0
1200  1
1320  1
1440  0
1560  0
1680  1
1800  0
1920  1
第一列以秒为单位显示时间,第二列显示状态(1为开,0为关)

我需要知道最多1秒的600秒是多少。例如,0-600有3*120秒,所以组件处于打开状态时为360秒。但120-720有4个等。。。这意味着,这不仅是0-600,600-1200,它可以通过任何600秒。困难的是,这是一个周期,意味着最糟糕的时间可能是从1920到480(注意,这个周期有2040,意味着时间2040也是时间0)。时间步长并不总是相等的。在这种情况下,它是一个常数120秒,但它可以是120秒和150秒的混合

我能想到的唯一一件事就是从0-600扫描文件,检查时间是开着的,120-720,240-840等等。。。但这非常耗时。特别是因为我可以有很大的文件

程序是用Perl编写的,但我只需要算法(如果存在的话)。你们中有谁知道什么是最好的方法吗


谢谢

问题可以通过以下方式解决。
定义一个整数n;继续将1与n相加,直到出现零。也就是说,如果出现零,则将n设置为零。在该过程中,记录最大n次出现次数和当时的秒数。为此,请定义另一个变量m,并将m设为最大值。如果n大于m,那么m=n。通过这种方式,您可以获得接近600秒的间隔,其中包含最大数量的1。祝你好运我希望它能起作用。

假设点是按时间排序的,您可以保留连续点的缓冲区,使第一个点和最后一个点之间的时间差不超过600。下面是C#中的代码:

//数据点的类
类点{
公共整数时间{get;私有集;}
{get;private set;}上的公共布尔
公共点(整数时间,布尔开){
时间=时间;
开=开;
}
}
点[]点={
新点(0,正确),
新点(120,正确),
新点(240,错误),
新点(360,错误),
新点(480,正确),
新点(600,正确),
新点(720,正确),
新点(840,错误),
新点(960,错误),
新点(1080,错误),
新点(1200,正确),
新点(1320,正确),
新点(1440,错误),
新点(1560,错误),
新观点(1680,正确),
新点(1800,错误),
新观点(1920年,正确),
};
int GetMaxIntervalCount(IEnumerable点){
LinkedList buff=新建LinkedList();
int buffCount=0,res=-1;
foreach(点对点){
buff.AddFirst(点);
而(buff.Count>0){
最后一点=buff.last.Value;
if(Math.Abs(last.Time-point.Time)>600){
buff.RemoveLast();
如果(最后一天){
--buffCount;
}
}否则{
打破
}
}
如果(开点){
++buffCount;
}
res=数学最大值(res,buffCount);
}
返回res;
}
目前,它只返回最大计数,但也可以轻松调整以保持实际缓冲区。方法的时间复杂度为O(N)(每个点
“触摸”最多2次-在缓冲区中添加和删除)。

不太清楚您试图计算的值,但您的核心问题似乎是找到一种算法来获取每个滑动600秒窗口中的样本。滑动窗口可以实现为一个数组。将新样本添加到末尾并清除旧样本以保持总大小,固定时间步长为120秒,您可以扫描文件,直到找到具有5个匹配项的块,因为这保证是最大值。如果没有包含5个匹配项的块,则只能读取整个文件。在平局的情况下,如果要报告具有最大值的所有块,而不是仅报告第一个块,则还必须读取整个文件。如果没有固定的时间步长,您也别无选择,只能读取整个文件。请显示当您环绕一个周期时,数字是如何变化的。还请解释当时间间隔从120变为150时,算法应该做什么-我们不能将
1
插值为
1
的120/150分之一,可以吗?至于周期,假设在1920年代之后,你有2040,但2040也是0,因为它是一个周期。对于时间步长,您可以计算它。从0到120,我有一个1,所以是120秒。您可以添加所有内容,直到达到>1h的时间。您可以先询问600s窗口中的on(1)样本数,然后讨论该窗口的总on时间。你想要哪个?假设是后者,应如何计算准时?e、 g.它在480秒和600秒时都是打开的,所以大概在这两者之间的整个120秒都是打开的。它在360秒时关闭,在480秒时打开:这应该算作0秒、120秒、60秒(平分差额)吗?同样,它在120秒时打开,在240秒时关闭;该如何计算呢?您声明0-600有3*120,120-720有4,但如果查看数据,6个周期的两个窗口都包含相同数量的1。是否有一个特定的规则来计算一个周期的时间?如果它是360秒,120秒,然后又是120秒呢。你的态度会给我360分而不是480分。就是这样,它可能不是连续的。正如我对之前的评论所作的回答:如果它是在360秒,120秒,然后又是120秒呢。你的态度会给我360秒而不是480sYep,这是正确的选择。谢谢据我所知,它被称为移动平均线。有一个非常聪明的perl代码:@Moose1231:它不是真正的移动平均值,但基本思想(查看从大量数据流中提取的移动子集)是相同的。
// Class for data point
class Point {
    public int Time { get; private set; }
    public bool On { get; private set; }

    public Point(int time, bool on) {
        Time = time;
        On = on;
    }
}

Point[] points = {
    new Point(0, true),
    new Point(120, true),
    new Point(240, false),
    new Point(360, false),
    new Point(480, true),
    new Point(600, true),
    new Point(720, true),
    new Point(840, false),
    new Point(960, false),
    new Point(1080, false),
    new Point(1200, true),
    new Point(1320, true),
    new Point(1440, false),
    new Point(1560, false),
    new Point(1680, true),
    new Point(1800, false),
    new Point(1920, true),
};

int GetMaxIntervalCount(IEnumerable<Point> points) {
    LinkedList<Point> buff = new LinkedList<Point>();
    int buffCount = 0, res = -1;
    foreach (Point point in points) {
        buff.AddFirst(point);
        while (buff.Count > 0) {
            Point last = buff.Last.Value;
            if (Math.Abs(last.Time - point.Time) > 600) {
                buff.RemoveLast();
                if (last.On) {
                    --buffCount;
                }
            } else {
                break;
            }
        }
        if (point.On) {
            ++buffCount;
        }
        res = Math.Max(res, buffCount);
    }
    return res;
}
use strict;
use warnings;
use Data::Dump qw(pp);

my @window;
while (my $line = <DATA>) {
    chomp $line;
    my ($t, $on) = split / +/, $line;

    # add sample to sliding window
    push @window, { t => $t, on => $on};

    # limit window size to 600s
    while (1) {
        last if @window <= 1;

        my $start = $window[0]{t};
        my $stop  = $window[-1]{t};

        # account for time values being mod 2040
        if ($stop < $start) {
            $stop += 2040;
        }

        if ($stop - $start > 600) {
            # purge old sample from window
            shift @window;
        }
        else {
            last;
        }
    }

    # do something with @window
    pp \@window;
}

__DATA__
0    1
120  1
240  0
360  0
480  1
600  1
720  1
840  0
960  0
1080  0
1200  1
1320  1
1440  0
1560  0
1680  1
1800  0
1920  1
0    1
120  1
240  0
360  0
# no wrapping
[
  { on => 1, t => 0 },
  { on => 1, t => 120 },
  { on => 0, t => 240 },
  { on => 0, t => 360 },
  { on => 1, t => 480 },
  { on => 1, t => 600 },
]

# with wrapping
[
  { on => 0, t => 1560 },
  { on => 1, t => 1680 },
  { on => 0, t => 1800 },
  { on => 1, t => 1920 },
  { on => 1, t => 0 },
  { on => 1, t => 120 },
]