206J(2/2). Reverse Linked List
what to do? think about recursion method.
Reverse a singly linked list.
Example:
Input: 1->2->3->4->5->NULL Output: 5->4->3->2->1->NULL
Follow up:
A linked list can be reversed either iteratively or recursively. Could you implement both? No
最好的方法是破坏性的iteration; T O(N) S O(1) recursive 比较优雅一点。
Method 1: Iteration Non-destructive
Class Learned:
可以用 ListNode p = null; 来新建空指针。
其实很简单,我们需要两个指针来指同一个链表。用一个复制对应的Node并链接另一个。
再把另一个重新指回新List。
class Solution {
public ListNode reverseList(ListNode head) {
ListNode p = head;
ListNode pr = null;
ListNode pr2 = pr;
while(p != null) {
pr = new ListNode(p.val);
pr.next = pr2;
pr2 = pr;
p = p.next;
}
return pr;
}
}
Method 2 : Iteration destructive
核心的思想还是从前到后转变指针方向,然后返回最后一个指针。 即 1 -> 2 -> 3; 1 <- 2 <- 3; 从3 开始返回
用破坏的方法也可以 原理是运用双指针。
先排除空链表和只有一个元素的链表,直接返回。
然后用两个指针p p2固定住前两节,并且直接把第一节断开。
p2 进行循环的时候,需要用一个temp ListNode把p2.next固定住,以防被垃圾回收找不到地址。
这样将指针排好序复位即可。
Iteration的方法只能够从前到后改变Node的指向,不能够回退。若想回退是需要用recursion的。
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode p = head;
ListNode p2 = head.next;
p.next = null;
while (p2!=null){
ListNode temp = p2.next;
p2.next = p;
p = p2;
p2 = temp;
}
return p;
}
}
代码二,原理相同,相对更优雅。是原答案。
prev的效果相当于dummyhead, 因此规避了问题。
```Java
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode nextTemp = curr.next; curr.next = prev; prev = curr; curr = nextTemp;
}
return prev;
}
## Method 3: Recursion
<pre>
* Recursive 方法实际上是将 指针从后往前翻转。
* 1 -> 2 -> 3 -> 4 -> 5
* 1 -> 2 -> 3 -> 4 <-> 5 即 5 指回 4
* 1 -> 2 -> 3 -> 4 <- 5 即 4 下一个指向 null
* 1 -> 2 -> 3 <-> 4 <- 5 即 4 指回 3
* 1 -> 2 -> 3 <- 4 <- 5 即 3 下一个指向 null
* 以此类推
* 判断中有两个语句, head == null 是用来排除空ListNode的。
head.next == null 是判断取到了最后一个Node的。
* ListNode p = reverseList(head.next); 相当于是直接将p指向了最后一位。
* 第一个返回的 p 是 List的最后一节。此时head指向倒数第二节。head.next 其实就是 p.
但是不能用 p.next 代替 head.next. 因为 p 的位置事实上是不变的,变的只是 head。
* p 一直指着原List的末尾,而head不停的回退,并且每一步都先向下连next两步自指,
然后将自己的下一步指向null. 这样就成功的翻转了一节。由于递归,回自动回到上一节。
从后往前逆转List的指针,是只能用递归的。
注意: 代码中的 head == null 判断只是为了防止空head输入。真正重要的
是 head.next == null 的判断。这使得 p 一直指在尾部node,而不是null.
</pre>
```Java
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}else{
ListNode p = reverseList(head.next);
head.next.next = head;
head.next = null;
return p;
}
}
Java Visualizer
这个代码进入Java Visualizer 可以直观感受这个递归是怎么工作的。
public class ListNode{
public int val;
public ListNode next;
public ListNode(int n){
val = n;
}
public void add(int n){
ListNode p = this;
while(p.next!=null){
p = p.next;
}
p.next = new ListNode(n);
}
static ListNode reverse(ListNode head) {
if (head.next == null) return head;
ListNode last = reverse(head.next);
head.next.next = head;
head.next = null;
return last;
}
public static void main(String[] args) {
ListNode test = new ListNode(1);
test.add(2);
test.add(3);
test.add(4);
test.add(5);
ListNode k = reverse(test);
}
}
Last updated
Was this helpful?