题目:
https://leetcode-cn.com/problems/reverse-linked-list/
题解一:
迭代+头插法。开辟一条新链表,遍历旧链表,逐个插入到新链表的头部。时间复杂度:O(n)。
public ListNode reverseList(ListNode head) {
// 哨兵节点
ListNode node = new ListNode();
while (head != null) {
ListNode newNode = new ListNode(head.val);
newNode.next = node.next;
node.next = newNode;
head = head.next;
}
return node.next;
}
该方法核心在于头插法的使用,逻辑简单,但是每次都需要开辟新的结点,浪费空间。
题解二:
双指针法。一个指针指向当前结点 current,一个指针指向前结点前一结点 pre,两个指针同时向后遍历,并修改指针指向。时间复杂度:O(n)。
public ListNode reverseList(ListNode head) {
// 临时结点
ListNode temp;
// 前结点
ListNode pre = null;
// 当前结点
ListNode current = head;
while (current != null) {
// 先保存当前结点的next
temp = current.next;
// 改变指针指向
current.next = pre;
// 移动指针
pre = current;
current = temp;
}
return pre;
}
注意:
1.在改变指针指向之前需要保存当前结点的next指向。
2.遍历结束后,current 指向 null,pre 指向的就是原链表最后一个结点,也就是翻转后新链表的第一个结点。
题解三:
双指针+递归。用递归实现双指针解法,时间复杂度:O(n)。
public ListNode reverseList(ListNode head) {
// pre = null, current = head
return reverse(null, head);
}
public ListNode reverse(ListNode pre, ListNode current) {
// 递归边界
if (current == null) {
return pre;
}
// 保存当前结点的next
ListNode temp = current.next;
// 改变指针指向
current.next = pre;
// 移动指针并递归
return reverse(current, temp);
}
思想和题解二一样,移动指针的同时改变指针指向,当 current 指向 null 时表示已经遍历到链表末尾,应该结束递归,返回头结点。