题目描述
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
来自leetcode: https://leetcode-cn.com/problems/reverse-linked-list/
链表中节点的数目范围是 [0, 5000]
-5000 <= Node.val <= 5000
栗子:
输入:head = [1, 2,3]
输出:[3,2, 1]
问题解决
1.方法一
边遍历原链表进行取值,边创建一个新链表进行头插即可。(前提,没有要求空间复杂度)
代码如下(示例):
public ListNode reverseList(ListNode head){
if(head==null||head.next==null){
return head;
}
//创建新链表的虚拟头节点
ListNode dummyHead=new ListNode(5001);
// 边遍历原链表,边头插新链表
while(head!=null){
ListNode node=new ListNode(head.val);
node.next=dummyHead.next;
dummyHead.next=node;
head=head.next;
}
return dummyHead.next;
}
2.方法二
原地移动(此时空间复杂度为O(1)–只能改变原链表的指向)
边遍历原链表,边让原链表的next不再指向后继转而指向其前驱。
因为牵扯到两个节点的反转指向,所以需要定义两个引用
cur-表示当需要处理的节点
prev-当前节点的前驱
cur.next=prev;(反转指向)
代码如下(示例):
public ListNode reverseList(ListNode head) {
if(head==null||head.next==null){
return head;
}
ListNode prev=null;
//当前需要处理的节点(需要反转)
ListNode cur=head;
while(cur!=null) {
//暂存下一个需要处理的节点
ListNode next=cur.next;
cur.next=prev;
prev=cur;
cur=next;
}
return prev;
}
注:1.暂存下一节点的原因:在操作完cur.next=prev之后,cur与连接到原来的链表就断开了,要进行下一次的两个节点的反转,就会找不到下一个节点,所以需要先用next来暂存。
3.方法三
为什么可以使用递归?
1.把反转链表这个大问题拆成两个子问题, 一个是头节点,另一个是除了头节点剩下的子链表。
2.子问题的求解方式和大问题一样。
3.存在最小子问题,即只剩一个节点,便不用再反转。
传入一个以head为头节点的链表方法就可以将此链表反转并且返回反转后的链表头节点
public ListNode reverseList(ListNode head) {
//递归终止条件
if(head==null||head.next==null){
return head;
}
ListNode sec=head.next;
//反转第二个节点之后的子链表
ListNode newHead=reverseList(head.next);
sec.next=head;
head.next=null;
return newHead;
}
需要注意的是
头节点的下一个节点必须指向 null。如果忽略了这一点,链表中可能会产生环。
链表具有天然的递归性质。