hiho一下第270周《模拟降水》题目分析

0
0

《模拟降水》题目分析

本题是一道非常难的模拟题。它改编自网上流传的一道著名的Airbnb的面试题。

首先我们大致分析一下,降水过程中水平面是怎么变化的。

第一,任何时刻,最多有2个"区间"的水平面在匀速上升,但是这两个区间上升的速率可能不同。这里"区间"指的的是若干个连续"区域"(区域是题目中的定义)组成的范围。我们称这样的区间是"激活区间"。

第二,当某个激活区间区间的水位上升到极限之后,可能会发生如下2种情况:

1) 激活区间扩展,也就是与相邻的区间合并,组成一个更大的水平面一致上升的区间。

2) 激活区间转移,也就是当前区间水平面不再上升,而另一个区间会平面开始上升。

我们以下图为例:

*
*   *
**  *
** ** * *
*********
123456789

假设在5号区域降水,一开始激活区间是[3, 3]和[6, 6]。

随着[3, 3]和[6, 6]水位上升到极限,激活区间变成[3, 4]和[8, 8]:

*
*   *
**  *
**W**W* *
*********
123456789

其中[3, 3] -> [3, 4]就是激活区间的扩展,[6, 6] -> [8, 8]就是激活区间的转移。

所以我们可以将整个降水过程划分成若干个阶段,每个阶段内激活区间不发生变化,只有激活区间的水位上升。

而一旦发生激活区间变化,就是另一个阶段的开始。

我们可以把所有N个区域划分成若干个区间,其中有(不超过)2个是激活区间。我们维护每个区间的范围以及当前的水位、极限的水位。

这样每一个阶段内的变化是容易计算的,只要我们知道这个阶段的激活区间是哪里,就能算出何时水位达到极限。

于是本题的难点就在于,当一个激活区间水位上升到极限时,如何计算下一个激活区间的范围。

这里需要根据2之前提到的2种不同的情况分别处理,其中第一种情况涉及区间的合并。

1 answer(s)

0

/** * * @param {从1开始各位初始水滴高度} initData 例如[1,2,3,5,7] * @param {滴水位置} site 例如 1 * 返回激活区间,例如:[[1,1],[2,3]] */ function findActivationInterval(initData, site) { if(!initData||initData.length<=0||!site||site>initData.length||sit<0){ console.log('参数输入错误'); } let key = site - 1;//位置对应索引 const left = { left: key, right: key };//左边区间 const right = { left: key, right: key };//右边区间 //右边区间 for (key = site; key < initData.length; key++) { if (initData[right.right] < initData[key]) { break; } else if (initData[right.right] === initData[key]) { right.right = key; } else { right.left = key; right.right = key; } } //左边区间 for (key = site - 2; key>-1; key--) { if (initData[left.right] < initData[key]) { break; } else if (initData[left.right] === initData[key]) { left.left = key; } else { left.left = key; left.right = key; } } if (left.right == right.left) { return [[left.left+1, right.right+1]]; } else if (left.right == site - 1) { return [[right.left+1, right.right+1]]; } else if (right.left == site - 1) { return [[left.left+1, left.right+1]]; } else { return [[left.left+1, left.right+1], [right.left+1, right.right+1]]; } }

write answer 切换为英文 切换为中文


转发分享