给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2] 输出:[2,1]
示例 3:
输入:head = [] 输出:[]
如果在定义一个新的链表,实现链表元素的反转,其实是对内存空间的浪费。
其实只需要改变链表的next指针的指向,直接将链表反转,而不需要定义一个新的链表,如图所示:
之前链表的头节点是1,反转之后的头节点是5,这里并没有添加或者删除节点,仅仅是改变了next指针的方向。
接下来看一下链表是如何反转的。
双指针法:
首先定义一个cur指针,指向头节点,再定义一个pre指针,初始化为null,接下来开始反转:
首先使用tmp指针保存cur->next,接下来改变cur->next的指向,将cur->next指向pre。
然后循环执行以上逻辑,继续移动pre和cur指针。
最后cur指针指向了null,循环结束,链表也反转完毕。此时我们返回pre指针即可,pre指针就指向了新的头节点。
代码:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode tmp=null;
ListNode pre=null;
ListNode cur=head;
while(cur!=null){
tmp=cur.next;
cur.next=pre;
pre=cur;
cur=tmp;
}
return pre;
}
}
递归法:
递归法其实和双指针的逻辑是一样的,同样是当cur为空的时候循环结束,不断将cur指向pre的过程。
关键在初始化的地方,双指针初始化cur=head,pre=null,递归法中其实是一样的,只是写法改变了:
// 递归
class Solution {
public ListNode reverseList(ListNode head) {
return reverse(null, head);
}
private ListNode reverse(ListNode prev, ListNode cur) {
if (cur == null) {
return prev;
}
ListNode temp = null;
temp = cur.next;// 先保存下一个节点
cur.next = prev;// 反转
// 更新prev、cur位置
// prev = cur;
// cur = temp;
return reverse(cur, temp);
}
}