题目描述
难度:简单
tags:链表、反转
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例 1:
**输入:**head = [1,2,3,4,5] 输出:[5,4,3,2,1]
示例 2:
**输入:**head = [1,2] 输出:[2,1]
示例 3:
**输入:**head = [] 输出:[]
题解
主要思路:把链表的箭头方向全部掉头
想象你有一条由若干个节点组成的链表,每个节点都有一个箭头指向下一个节点。
原链表结构为:1 → 2 → 3 → 4 → 5 → null
你的任务就是,把所有的箭头方向都原地掉头,让最后一个节点变成第一个,第一个变成最后一个。
反转后的链表结构为:null ← 1 ← 2 ← 3 ← 4 ← 5
也就是说: 输入:1 → 2 → 3 → 4 → 5 → null 输出:null ← 1 ← 2 ← 3 ← 4 ← 5
不难发现,之前指向 null 的尾结点【5】变成了头结点,之前的头结点变成了指向 null 的尾结点。
而中间的箭头方向反转如何体现?
我们可以单独拎出来一个结点观察一下,对于【3】这个结点,可以发现,【3】的 next 从指向下一个结点【4】,变成了指向上一个结点【2】。
再观察所有的结点,发现 1.除了头结点之外,每个结点的 next 都从指向下一个结点,变成了指向上一个结点。
那么头结点与其他结点有什么不同?
显然,头结点【1】的 next 从指向下一个结点【2】变成了指向 null。 也就是说,2.头结点从指向下一个结点转而指向 null。
代码思路
刚才已经总结出来 2 条结论:
- 除头结点之外,每个结点的 next 都从指向下一个结点,变成了指向上一个结点。
- 头结点从指向下一个结点变成指向 null。
我们利用这两条结论来组织代码,令当前正在操作的节点为 cur,cur 的下一个结点为 nxt,cur 的上一个结点为 pre。
这里可能会产生一些疑问,头结点【1】的上一个结点 pre 为什么要指向 null?
其实这是为了将刚刚得到的两条结论统一组织成代码。
- 除头结点外,每个结点都从指向下一个结点,变成了指向上一个结点。
- 头结点从指向下一个结点变成指向 null。
那我们就直接将头结点的上一个结点 pre 指定成 null。
这样每个结点的核心反转代码就可以统一成 cur.next=pre,不用针对头结点另写代码了。
解题步骤如下:
- 从头结点开始反转,让 cur 指向头结点,pre 指向 null。(让 cur 从头结点开始遍历,一直遍历到尾结点,可以将每个结点的 next 指向都反转) 也就是:cur=head;pre=null;
遍历的终点是,cur 指向 null
重复第 2、3、4 步
更改完 next 的指向之后,移动 cur 和 pre,让 pre 指向 cur,让 cur 指向事先保存的 nxt 也就是:pre=cur;cur=nxt;
针对每个结点,让 nxt 指向头结点的下一个结点 cur.next,让 next 从指向下一个结点,变成指向上一个节点 pre (nxt 的作用:事先保存 cur 的下一个结点,以免 cur 在改变 next 的指向后,找不到 cur 原先的的下一个结点) 也就是:nxt=cur.next;cur.next=pre;
至此,就完成了链表反转。
代码(Java 版)
/**
* 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; }
* }
*/
{
ListNode {
;
head;
(cur != ) {
cur.next;
cur.next = pre;
pre = cur;
cur = nxt;
}
pre;
}
}


