# 206.反转链表
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例 1:
输入: head = [1,2,3,4,5]
输出:[5,4,3,2,1]
示例 2:
输入: head = [1,2]
输出:[2,1]
示例 3:
输入: head = []
输出:[]
提示:
- 链表中节点的数目范围是
[0, 5000]
-5000 <= Node.val <= 5000
进阶: 链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?
解题
解法一(双指针迭代)
思路分析:
- 首先考虑
head == null
的情况,此时直接返回null
- 然后使用两个指针,指针
p
在前,指针q
在后,将指针q
的指向改为指向p
,即q.next=p
,完成反转 - 然后再依次移动指针
p
和指针q
,当遍历结束后,q=null
已经没有需要反转的节点,p
则刚好指向最后一个节点,即反转链表的第一个节点;将其返回
实现代码如下:
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null) // head为空 直接返回
return null;
// p为q的前一个节点
ListNode p = head;
ListNode q = head.next;
while (q != null) {
ListNode t = q.next; // 记录下q的下一个节点
q.next = p; // 改变节点的指向 将其反转指向前一个节点
p = q; // 重新移动p为 未反转节点的前一个节点
q = t; // 移动q到还未反转的节点
}
head.next = null; // 第一个节点的指向需要改为空
return p; // 返回新的头节点 即原链表的尾节点
}
}
提交结果如下:
解答成功:
执行耗时:0 ms,击败了100.00% 的Java用户
内存消耗:39.9 MB,击败了91.80% 的Java用户
复杂度分析:
- 时间复杂度:O(n),即遍历原链表
- 空间复杂度:O(1),使用常量级变量
解法二(递归)
思路分析:
- 首先一直递归,知道递归到最后一个节点,此时最后一个节点的下一个节点为空,直接返回即可
- 然后返回的新链表是已经反转好的链表,并且返回的是头节点,此时的
head
,指向的是已经反转好的链表的最后一个节点,改变其方向,将其指向自己 - 即将此时的节点
head
加入到反转链表中,并将其指向的值更改为null
- 最后依次回调
实现代码如下:
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) // head为空 直接返回
return head;
ListNode p = reverseList(head.next);
head.next.next = head;
head.next = null;
return p;
}
}
提交结果如下:
解答成功:
执行耗时:0 ms,击败了100.00% 的Java用户
内存消耗:40 MB,击败了83.06% 的Java用户
复杂度分析:
- 时间复杂度:O(n)
- 空间复杂度:O(1)