仅使用推送和删除操作将列表从顺序 A 修改为顺序 B
是否有任何众所周知的算法(或明显的解决方案)仅使用 push
和 remove
操作将列表从顺序 A 转换为顺序 B?例如,从 abc d
到 bca d
可以使用以下操作完成:
remove(a)
remove(d)
push(a)
push(d)
或者,从 cb a
到 a b 将是
remove(c)
remove(b)
push(b)
或者,从 ac b
到 acb d
将是
push(d)
这里,push
将一个元素追加到列表末尾,并且 < code>remove 删除元素并移动后续元素,使列表始终处于连续状态(没有“空槽”)。此外,还有一个条件是,在任何给定时刻,列表中的相同元素只能包含一次。因此,首先在一组中执行所有remove
,然后再执行所有push
,这似乎是合理的。显然,remove
的顺序并不重要,但 push
的顺序却很重要。
一个简单的解决方案是首先删除所有元素,然后按所需的顺序推送所需的元素。但由于我知道大多数时候转换会非常小,相当于单个 push
es 或 remove
s,所以我想“重用”任何现有的正确顺序列表(例如,将 abcdef
转换为 abcde
只需要一次 remove
操作 - 与替代方案(6+5 操作)有很大不同)。那么,如何得出正确的(最小)remove
集合和push
列表呢?
Is there any well-known algorithm (or obvious solution) for transforming a list from order A to order B using only push
and remove
operations? For instance, from a b c d
to b c a d
could be done using the following operations:
remove(a)
remove(d)
push(a)
push(d)
Or, from c b a
to a b
would be
remove(c)
remove(b)
push(b)
Or, from a c b
to a c b d
would be
push(d)
Here, push
appends an element to the end of the list, and remove
removes the element and shifts the subsequent elements so that the list is always in continuous state (no "empty slots"). Additionally there's a condition that at any given moment the list may contain the same element only once. Therefore it seems sound to first do all remove
s in one bunch, and all push
es after that. The order of remove
s obviously doesn't matter, but the order of push
es does.
A trivial solution would be to first remove all elements and then push the desired elements in the desired order. But since I know that most of the time the transforms will be quite small, equivalent to single push
es orremove
s, I want to "reuse" any existing correct order in the list (for instance, transforming abcdef
to abcde
would require just one remove
operation - quite a difference to the alternative (6+5 operations)). So, how to come up with the right (minimum) set of remove
s and list of push
es?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
据我所知,你将从任何地方移开并推到后面。
由于无法插入到列表的中间,因此最小化操作次数的唯一方法是线性遍历列表并删除任何不正确的元素。
即1、2、3、4、5、6、7、8、9、10→ 2, 4, 6, 7, 8, 13, 14
(已结束)
如果你的推送没有那么有限,会有更有效的方法来做到这一点。
From what I can tell, you are going to be removing from anywhere and pushing to the back.
Because you can't insert into the middle of the list, the only way you can minimize the number of operations is to go through the list linearly and remove any element that is not correct.
i.e. 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 -> 2, 4, 6, 7, 8, 13, 14
(reached end)
If your push wasn't so limited, there would be more efficient ways of doing this.
这并不是“众所周知”,而是我刚刚想到的。
删除
原始列表中不存在的所有元素;将每个删除操作添加到操作列表中。添加
工作中缺少的任何元素;将每个添加操作添加到操作列表中。删除
此范围之外位置的所有元素并将它们放入其他临时列表中;将每个删除操作添加到操作列表中。添加
元素;将每个添加操作添加到操作列表中。因为您只能添加和删除——不能插入元素或添加/删除范围——我认为您不能保留任何有序子段的现有顺序 除了 0 中的有序段之外。这就是在步骤 4 中删除所有其他元素的原因。由于您不必在删除后立即添加这些元素(根据您的示例),我认为可以将它们存放在某个地方。那么,为什么不将它们存储在可排序列表中并根据分配的“订单号”进行排序以确定添加的顺序呢?
除非我误解了你的问题,否则你对添加/删除操作的顺序感兴趣,所以你不关心实际转换列表(因为你已经有了转换后的列表);您想要创建转换列表的步骤。因此,每次在算法中添加或删除时,请将“操作”添加到操作列表(队列)中(例如
operations.Add("remove(a)")
)。然后算法返回该操作列表。我用 C# 编写了一个可能的实现。我对其进行了一些测试(下面的屏幕截图),它似乎有效。然而,它也可能不是某人可以编写的最佳实现。
This isn't "well known", but rather something I just thought up.
Remove
all elements from the original that are not in the desired list; add each remove operation to the list of operations.Add
any elements to working that are missing; add each add operation to the list of operations.Remove
all elements at positions outside of this range and put them in some other temporary list; add each remove operation to the list of operations.Add
the elements in order from the temporary list; add each add operation to the list of operations.Because you can only add and remove--not insert elements or add/remove a range--I don't think you can keep the existing order of any in-order sub-segments other than the in-order segment from 0. That's why all other elements are removed in step 4. Since you don't have to add those elements immediately after removing (based on your example), I assume it's ok to store them somewhere. So, why not store them in a sortable list and sort based on the assigned "order number" to determine the order of adds?
Unless I've misunderstood your question, you're interested in the order of add/remove operations, so you don't care about actually transforming the list (since you already have the transformed list); you want the steps to create the transformed list. Therefore, each time you add or remove in the algorithm, add the "operation" into a list (queue) of operations (e.g.
operations.Add("remove(a)")
). The algorithm then returns this list of operations.I wrote a possible implementation in C#. I tested it a little (screen shots below) and it seemed to work. It might also not be the best implementation that someone could write, however.
头脑风暴:
也许您可以使用笛卡尔树来确定操作顺序,如下所示(经过编辑以修复在完成以下示例时发现的错误):
让我们尝试一个例子:
I '将使用维基百科页面中的笛卡尔树中的示例:
开始时:
首先循环:
第二个循环:
完成。
Brainstorming:
Perhaps you can use a Cartesian tree to determine the order of operations as follows (edited to fix bugs discovered when working through the example below):
Let's try an example:
I'll use the example from the Wikipedia page for Cartesian trees:
At start:
First loop:
Second loop:
Done.