给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例 1:
ini
输入: head = [1,2,3,4,5]
输出: [5,4,3,2,1]
示例 2:
ini
输入: head = [1,2]
输出: [2,1]
示例 3:
ini
输入: head = []
输出: []
提示:
- 链表中节点的数目范围是
[0, 5000]
-5000 <= Node.val <= 5000
进阶: 链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?
java
class Solution {
public static void main(String[] args) {
ListNode node = new ListNode(0);
node.next = new ListNode(1);
node.next.next = new ListNode(2);
node.next.next.next = new ListNode(3);
node.next.next.next.next = new ListNode(4);
reverse(node);
}
public ListNode middleNode(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null || fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
public static ListNode reverse(ListNode head) {
ListNode cur = head;
ListNode pre = null;
while (cur != null) {
//暂存后继节点 cur.next=1
ListNode tmp = cur.next;
//将原来的头结点给cur的下一个节点
cur.next = pre;
//将当前cur作为pre也就是头结点,也就是遍历到谁谁就是头结点,原来的头结点要给到当前正在遍历的节点的下一个节点
pre = cur;
//假设pre=0 cur=1 cur.next=2
//那么经过上面的操作以后,cur.next=0, pre = cur = 1 即 pre=1,pre.next=0 相当于是做了换位操作
cur = tmp;
}
return pre;
}
}
方法一:迭代
假设链表为 1→2→3→∅ 我们想要把它改成 ∅←1←2←3。
在遍历链表时,将当前节点的 next\textit{next}next 指针改为指向前一个节点。由于节点没有引用其前一个节点,因此必须事先存储其前一个节点。在更改引用之前,还需要存储后一个节点。最后返回新的头引用。
java
class Solution {
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
}
时间复杂度:O(n)
其中 nnn 是链表的长度。需要遍历链表一次。
空间复杂度:O(1)。
方法二:递归
递归版本稍微复杂一些,其关键在于反向工作。假设链表的其余部分已经被反转,现在应该如何反转它前面的部分?
java
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode newHead = reverseList(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
}
复杂度分析
时间复杂度:O(n),其中 n 是链表的长度。需要对链表的每个节点进行反转操作。
空间复杂度:O(n),其中 n 是链表的长度。空间复杂度主要取决于递归调用的栈空间,最多为 n 层。