反转链表
所以我需要在 O(N) 时间/空间内反转链表。
这个实现是我仅使用 Java 标准库中的 LinkedList 类(它不允许我访问节点本身)实现的。
So I need to reverse a Linked List in O(N) time/space.
This implementation is what I came up with using only the LinkedList class in the Java standard library (which doesn't give me access to the nodes themselves).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
的事实
LinkedList
类具有方法addFirst
addLast
removeFirst
removeLast
其中每个都是 O(1)。
您可以通过多种方式获得 O(n) 时间和空间行为。其中一种方法是:
“就地”进行反转(即变量
a
始终引用完全相同的对象)。它相当于使用堆栈作为临时存储(b
是“堆栈”)。尽管复制很丑陋,但它的时间复杂度和空间复杂度都是 O(n)。
The "better way" you ask of can exploit the fact that the Java
LinkedList
class has methodsaddFirst
addLast
removeFirst
removeLast
Each of these are O(1).
You can get O(n) time and space behavior in a few ways here. One such way is:
This does the reversal "in place" (that is, the variable
a
references the exact same object at all times). It is equivalent to using a stack as temporary storage (b
is the "stack").It is O(n) time and O(n) space, despite the ugly copying.
不,不是。
input.get(idx);
本身的时间O(idx)
,这使得您的实现在时间上呈二次方。您可能想要使用迭代器(或者更好的
listIterator
)。编辑:此外,您可以通过一些重新排列轻松消除holdPopped。
holdPopped.add
在时间和空间上都是普通的 O(1),因为您通过传递大小来预分配空间(在空间中是 O(n))。IIRC,holdLL.add 在时间和空间上均摊为 O(1)。有时会多,有时会少,但总空间是n,所以平均应该是O(n)。您可以使用
holdLL.ensureCapacity
简化分析。No, it's not.
input.get(idx);
is itselfO(idx)
in time, which makes your implementation quadratic in time.You will probably want to use an iterator (or better yet
listIterator
).EDIT: Also, you could easily eliminate holdPopped with a little rearrangement.
holdPopped.add
will be trivially O(1) in both time and space since you're pre-allocating space (which is O(n) in space) by passing the size.IIRC,
holdLL.add
is amortized O(1) in time and space as well. Sometimes it will be more, sometimes less, but the total space is n, so it should average to to O(n). You can simplify the analysis by usingholdLL.ensureCapacity
.Java API 有一个方法可以在 O(n) 内完成此任务:
Collections.reverse(Listlist)
。假设这是家庭作业,您应该自己实现它,但在现实生活中您将使用库函数。或者,您可以创建一个反向装饰器,使反转的时间复杂度为 O(1)。下面是这个概念的一个例子。
请注意,让装饰器扩展具体类通常(总是?)是不好的形式。理想情况下,您应该实现公共接口并接受构造函数参数作为公共接口的实例。上面的例子纯粹是为了说明目的,因为 LinkedList 恰好实现了很多接口(例如 Dequeue、List 等)。
另外,在此处插入典型的“过早优化是邪恶的”注释 - 如果您的列表实际上是瓶颈,您只会在现实生活中创建此反向出列类。
The Java API has a method for this that completes in O(n):
Collections.reverse(List<?> list)
. Assuming this is homework you should implement this yourself, but in real life you would use the library function.Alternatively, you can create a reverse decorator which makes the reversal O(1). An example of the concept is below.
Note that it is generally (always?) bad form to make a decorator extend a concrete class. Ideally you should implement the public interface and accept a constructor parameter as an instance of the public interface. The above example is purely for illustration purposes, as the LinkedList happens to implement a lot of interfaces (e.g. Dequeue, List etc).
Also, insert the typical "Premature optimisation is evil" comment here - you would only create this reversed dequeue class in real life if your list was actually a bottleneck.
你应该经常检查apache commons,他们通常对链表和集合有更好、更灵活的实现;
https://commons.apache.org
其次,您使用 会更容易双向链表如果你想反转一个列表。
You should always check apache commons, they have better and more flexible implementations for the linkedlist and collections in general;
https://commons.apache.org
And secondly, it would be more easy for you to use a doubly linked list if you want to reverse a list.