思路1:迭代法(双指针)
将原链表节点一个一个摘下,再用头插法插入新链表中,新链表为带头结点(哨兵节点)的带头链表,带头结点的好处是,方便返回链表的首节点。
可参照代码注释和图一起看
class Solution {
public ListNode reverseList(ListNode head) {
//边界判断,链表为空或者一个节点直接返回
if(head==null||head.next==null)
{
return head;
}
//带头节点的新链表
ListNode dummy=new ListNode(-1);
//当前节点指向原链表的头
ListNode cur=head;
//原链表存在节点则循环继续
while(cur!=null)
{
//断开当前节点,原链表头后移
head=head.next;
//当前节点指向新链表的“首”节点,不是头结点哦,头结点始终是dummy
cur.next=dummy.next;
//新链表的头结点的指向为刚刚插入的节点
dummy.next=cur;
//当前节点又指回原链表当前的头
cur=head;
}
//返回新链表的的首节点
return dummy.next;
}
}
时间复杂度O(n),空间复杂度O(1)
思路2:三指针,原链表直接反转
指针cur指向当前需反转方向的节点,指针pre指向cur的前一节点(即cur反转之后需要指向的节点),指针nxt指向cur的下一节点,记录下一个需要反转方向的节点,以便赋值给cur
图结合代码看,图比较简陋,你可以自己在纸上模拟下
class Solution {
public ListNode reverseList(ListNode head) {
if(head==null||head.next==null)
{
return head;
}
ListNode pre=null;
ListNode cur=head;
ListNode nxt=cur;
while(cur!=null)
{
nxt=cur.next;
cur.next=pre;
pre=cur;
cur=nxt;
}
return pre;
}
}
时间O(N) 空间O(1)
思路3:递归法,递归不太好理解
注意递归几个要素
1、终止条件
2、递归公式
3、递归之后做什么,返回值
4、对于递归,你只需要知道相邻两层在干什么就行,比如最后一层和上一层,别把自己递进去!!!!
图结合代码看
class Solution {
public ListNode reverseList(ListNode head) {
//终止条件 无节点,一个节点直接返回
if(head==null||head.next==null)
{
return head;
}
//递归公式 找到链表的最后节点
ListNode last=reverseList(head.next);
//递归之后做什么 最后一个节点(即head.next,为什么) head.next的下一节点指向其前一节点,反向指向)
head.next.next=head;
//倒数第二个节点和最后一个节点断开,防止死循环
head.next=null;
//返回最后一个节点
return last;
}
}
时间复杂度O(n), 空间复杂度 O(n)递归栈