public static Node reverseLinkedList1(Node head) {
if(head == null) return null;
Node node = null;
while(head != null) {
Node newNode = new Node(head.data);
newNode.next = node;
node = newNode;
head = head.next;
}
return node;
}
public static Node reverseLinkedList2(Node head) {
if(head == null) return null;
Node node = null;
while(head != null) {
Node next = head.next;
head.next = node;
node = head;
head = next;
}
return node;
}
这两个算法是相同的空间复杂度吗?我知道第二个是0(1)的空间复杂度,第一个呢?O(N)还是O(1)?
第一个算法的空间复杂度为0 (N),因为您正在构建一个新的LinkedList
。
让我们用一个示例列表
来看看这个算法Node1 -> Node2 -> Node3 -> null
当您第一次进入while循环时,您将使用Node1
的数据创建一个新的节点Node1*
,并且没有对原始LinkedList
进行任何修改。您只是打乱了一些局部变量,导致
Node1 -> Node2 (head) -> Node3 -> null
node = Node1* -> `null`
在第二个while循环之后。注意,Node1仍然在原始列表中。
Node1 -> Node2 -> Node3 (head) -> null
node = Node2* -> Node1* -> null
第三次后
Node1 -> Node2 -> Node3 -> null (head)
node = Node3* -> Node2* -> Node1* -> null
此时,您有两个大小相同的列表。
当然,我只查看了Node
实例的数量。由于您在节点之间共享数据,因此实际开销并不是那么大。
第一种算法的好处当然是原始的LinkedList
仍然是完整的,而第二种算法则不是这样。
在第一种情况下,您正在创建N
新对象,因此您正在消耗O(N)
空间。在方法的最后,原始列表是still holding
引用,因为它被传递。您应该将这些引用设置为空,以便JVM可以使用garbage collection
。
我添加了一个单独的temp
变量来保存当前的head
,一旦我们提取head.next
,我们可以设置head.next=null
。由于现在这些对象不被任何人引用,因此将有资格进行垃圾收集。
public static Node reverseLinkedList1(Node head) {
if(head == null) return null;
Node node = null;
Node temp;
while(head != null) {
Node newNode = new Node(head.data);
newNode.next = node;
node = newNode;
temp = head;
head = head.next;
temp.next = null;
}
return node;
}