JavaScript:找到最大间隔重叠的点

时间:2021-02-10 06:37:06

标签: javascript arrays function

我的作业需要帮助,我遇到了这个问题,但不知道如何找到答案:

考虑一组退休人员,其中任何人在第 X 年开始工作并在第 Y 年退休。创建一个函数,该函数接收遵循以下结构的数组:[[x1,y1],[x2,y2],...[xn,yn]] 并计算哪一年( s) 大多数人都在工作。

考虑:

  • X 值是该人开始工作的年份 (x>0, x<y);
  • Y 值作为此人退休的年份 (y>0);
  • 必须将开始年份视为工作年份;
  • 退休年份必须被视为工作年份。

示例:Input [[1960,2005],[1945,2008],[1938,1999],...]

我试图将最低和最高年份进行比较,并逐年计算有多少人在工作,但没有成功。

编辑:我设法将数组转换为一个数组并对所有工作年份进行排序。现在我需要管理如何找到每年工作的人。我开发的代码如下:

var variety = [[2000,2008],[2003,2009],[2001,2012],[2004,2020],[2003,2021],[1998,2015]], year = [], anos2 = 0, k=0, minYear=0, maxYear=0
function getyear(people){
    for(var lin = 0; lin < people.length; lin++){ //Esse for é para transformar a matriz em um único vetor dinamicamente
        for(var col = 0; col < people.length-(people.length-2); col++){
            year[k] = people[lin][col]
            k++
        }
    }
    year.sort(compareNumbers) //Ordena o vetor dos anos trabalhados
    console.log(year)
    console.log(people)

}
function compareNumbers(a,b){
    return a -b
}
getyear(variety)

4 个答案:

答案 0 :(得分:2)

从您的问题来看,您似乎很难解决如何解决问题,而不是如何编写代码。希望以下见解对您有所帮助。

如何创建一个初始值为 0 的从 minYear 到 maxYear 的整数数组。 每当您有一个用户在 X 年开始工作并在 Y 年退休时,您只需将数组中每一年的数字递增。

因此,从 1960 年到 2015 年工作的人将在数组中为 1960 年到 2015 年的值提供值 1。对每个用户重复。

之后,您可以循环数组以查找数组中的最大值和最小值。这也简化了逻辑,因为可能有多个最大峰值和多个最小峰值。

还有一种替代方法,即不创建任何数组并从 minYear 到 maxYear 每年循环一次,从而不分配尽可能多的内存。对于那些年中的每一年,您都需要为所有员工循环以计算该年有多少人在工作。将第一年保存为最小值和最大值,每隔一年,如果该值高于最高值或低于最低值,只需更新它并将其用作新的峰值。这使用最少的内存,但会使用更多的 CPU。

总有一些替代方法可以实现更好的 CPU 和内存效率。但是对于初学者来说,这两种方法都是可以接受的。

答案 1 :(得分:1)

功能:

const getCounts = (arr = []) =>
{
    const years = {};
    let x, y, year;
    arr.forEach( item => {
        x = item[0];
        y = item[1];
        for ( year = x ; year <= y ; ++year )
        {
            if(years[year] === undefined)
            {
                years[year] = 0;
            }
            years[year]++;
        }
    });
    return years;
}

排序:

const output = getCounts([[1960,2005],[1945,2008],[1938,1999]]);

console.log( Object.entries(output).sort( (a,b) => b[1] - a[1] ) );

答案 2 :(得分:1)

以下方法利用了 this article 中描述的算法。与之前的答案不同,这不会将 all 范围不必要地分解为年份,也不会在每个范围内迭代每年。相反,它返回同时工作的最大人数,以及雇用该人数的一系列范围。如果需要,可以将范围数组转换为年份数组。

const f = input=>Object.entries(
  // sum up entries/exits by year
  input.reduce(
    (a,[s,e])=>(
      a[s] = (a[s]||0)+1,
      a[e] = (a[e]||0)-1,
      a
    ),{}
  ))
  // convert years back to numbers
  .map(([s,e])=>[1*s,e])
  // sort ascending by year
  .sort(([r],[l])=>r-l)
  .reduce((a,[y,c])=>{
    a.count += c;
    switch (Math
      .sign(a.count - a.r.max)) {
    case 1: // count > max
      // set max; clear ranges
      a.r = {max:a.count,ranges:[]};
      // fall through
    case 0: // count === 0
      // open new range
      a.r.ranges.push([y]);
      break;
    case -1: // count < max
      // close range, if open
      a.r.ranges.push([
        ...a.r.ranges.pop(), y
      ].slice(0,2));
      break;
    }
    return a;
  },{ // initial values
    count:0,
    r:{max:0,ranges:[]}
  })
  // return results object
  .r;

例如:

const input = [
  [1960,2005],
  [1945,2008],
  [1938,1999]
];

console.log(f(input1));

这将导致:

{ max: 3, ranges: [ [ 1960, 1999 ] ] }

表示同时雇用的最大工人数为 3,并且在 1960 年至 1999 年(含)期间同时雇用了 3 名工人。

在下面一个更复杂的例子中,为简洁起见,我多年来一直使用小整数:

const input = [
  [1,9],
  [1,2],
  [8,9],
  [2,3],
  [5,7],
  [7,9],
  [5,6],
  [8,9],
  [5,9],
  [4,8],
  [1,3]
];

console.log(f(input));

结果是:

{ max: 5, ranges: [ [ 5, 6 ], [ 8, 9 ] ] }

表示同时最大工人数为 5,并且在两个不重叠的时间间隔内同时雇用 5 名工人:第 5 年到第 6 年第 8 年到第 9 年。

如果需要,以下函数可用于将范围数组分解为年份的平面数组:

const explode = ranges=>
  [].concat(
    ...ranges.map(([s,e])=>Array.from(
      {length:e-s+1},(_,i)=>i+s
    ))
  );

例如:

const input = [
  [1,5],
  [6,7],
  [9,9]
];
  
console.log(explode(input));

将导致以下结果:

[ 1, 2, 3, 4, 5, 6, 7, 9 ]

答案 3 :(得分:0)

也许你可以这样做;

var years  = [[2000,2008],[2003,2009],[2001,2012],[2004,2020],[2003,2021],[1998,2015]];
    result = years.map(ys => Array.from({length:ys[1]-ys[0]+1}, (_,i) => ys[0]+i))
                  .reduce((p,c) => p.filter(e => c.includes(e)));

console.log(result);

years.map(ys => Array.from({length:ys[1]-ys[0]+1}, (_,i) => ys[0]+i))

part 将您的 [[2000,2008],[2003,2009],[2001,2012],[2004,2020],[2003,2021],[1998,2015]] 数组变成

[[2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008]
,[2003, 2004, 2005, 2006, 2007, 2008, 2009]
,[2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012]
,[2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020]
,[2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021]
,[1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015]
]

.reduce((p,c) => p.filter(e => c.includes(e))) 部分只是 reduces by intersecting

这只是一种幼稚但直观的方式。从这个想法发展而来,您应该能够通过一个 .reduce() 阶段来做到这一点。所以它仍然是一个家庭作业。

所以上面的解决方案对于给定的数据集是可以的,但是有一个正确的评论。所以我在这里切换到一个高效的代码。它返回一个对象,其中属性是受制于人们工作的年数,值是每年的人数。

var years = [[2000,2008],[2003,2009],[2001,2012],[2004,2020],[2003,2021],[1998,2015]];
    result = years.reduce(function(r,ys) {
                            for (var y = ys[0]; y <= ys[1]; y++){
                              r[y] = r[y] ? r[y]+1 : 1
                            }
                            return r;
                          },{});
console.log(result);
.as-console-wrapper {
max-height: 100% !important
}