任务是重新排列一个循环列表中的项目,如下所示:
LRLLLRLLLRRLLRLLLRRLRLLLRLLRLRLRLRRLLLRRRLRLLRLLRL
因此,我们将得到这样的列表:
RRRRRRLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLRRRRRRRRRRRRRR
或者这样:
LLLLLLLLLLLLLLLLLLLLLLLLLRRRRRRRRRRRRRRRRRRRRLLLLL
这里有两种类型的项目,它们被分组在一起,但是这两个组的确切位置并不重要。
第一个任务是计算每个组中项目的数量,因此我们需要遍历列表一次。对于上面的示例,结果如下:
那么,简单的暴力解决方案是将列表中的每个位置都视为L区域的起点,从位置0开始迭代整个列表,并计算每个项距离它应该在的区域边界有多少步:
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLRRRRRRRRRRRRRRRRRRRR <- desired output
LRLLLRLLLRRLLRLLLRRLRLLLRLLRLRLRLRRLLLRRRLRLLRLLRL <- input
< < << < >> > > > >< < <<< > >> >> > <- direction to move
我们现在将考虑L区从位置1开始,并重新进行整个计算:
RLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLRRRRRRRRRRRRRRRRRRR <- desired output
LRLLLRLLLRRLLRLLLRRLRLLLRLLRLRLRLRRLLLRRRLRLLRLLRL <- input
<< < << < >> > > > > < <<< > >> >> > <- direction to move
计算出L区每个位置的总步数后,我们就可以知道哪个位置需要最少的步数。当然,这是一种N2复杂度的方法。
如果我们能够在不再次迭代整个列表的情况下,基于位置X-1处L区的计算,计算出位置X处L区所需的步数,那么这将把复杂度降至N。
为了做到这一点,我们需要跟踪每个区域的两个半部分中错误项的数量,以及每个这四个半区域中错误项的总步数。
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLRRRRRRRRRRRRRRRRRRRR <- desired output
<<<<<<<<<<<<<<<>>>>>>>>>>>>>>><<<<<<<<<<>>>>>>>>>> <- half-zones
LRLLLRLLLRRLLRLLLRRLRLLLRLLRLRLRLRRLLLRRLRRLLRLLRL <- input
< < << < >> > > > >< < <<< > >> >> > <- direction to move
5 6 5 6 <- wrong items
43 45 25 31 <- required steps
当我们向右移动到下一个位置时,左移区域的总步数将减少该区域错误项的数量,右移区域的总步数将增加该区域错误项的数量(因为每个项现在距离该区域的边缘更近/更远,所以需要增加/减少相应的步数)。
5 6 5 6 <- wrong items
38 51 20 37 <- required steps
然而,我们需要检查四个边界点,看看是否有任何错误的项目从一个半区移动到另一个半区,并相应地调整项目和步骤计数。
在这个例子中,原来是 L 区域的第一个项目 L 现在成为了 R 区域的最后一个项目,因此我们将 R> 半区的项目和步骤计数增加到 7 和 38。
另外,原来是 R 区域的第一个项目 L 现在成为了 L 区域的最后一个项目,因此我们将 R< 半区的项目计数减少到 4。
另外,R 区域中间的 L 从 R> 半区移到了 R< 半区,因此我们将 R> 和 R< 的项目计数分别减少和增加到 6 和 5,并将步骤计数减少和增加 10(R> 和 R< 半区的长度)到 28 和 30。
RLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLRRRRRRRRRRRRRRRRRRR <- desired output
><<<<<<<<<<<<<<<>>>>>>>>>>>>>>><<<<<<<<<<>>>>>>>>> <- half-zones
LRLLLRLLLRRLLRLLLRRLRLLLRLLRLRLRLRRLLLRRLRRLLRLLRL <- input
>< < << < >> > > > > < <<< < >> >> > <- direction to move
5 6 5 6 <- wrong items
38 51 30 28 <- required steps
当L区从位置0开始时,所需步骤的总数为144。我们已经计算出当L区从位置1开始时,通过查看列表中四个位置发生的情况,而不是必须再次迭代整个列表,总数现在为147。
更新
在考虑如何实现此功能时,我意识到,在一个区域中向右移动的错误项数必须与在另一个区域中向左移动的错误项数相同;否则,区域之间的边界就会出现问题。这意味着L和R区域并没有分成两个等长的半区域,并且区域中的“中点”将根据其左侧和右侧的错误项数量而移动。我仍然认为可以将其转化为具有O(N)效率的工作代码,但可能不像我最初描述的那么简单。