链表题中,链表反转应该是出现频率最高的一道题。
如何实现?
我们分析一下,一个链表,【1, 2,3,4,5】,反转成 【5,4,3,2,1】,我们可以适应循环。
循环的过程中,将当前节点的 next 指向上一个 pre 节点,假设当前节点是 2,那么反转之后,2 的 next 就是 1。但是这是一个单向链表,他是没有 pre 属性的 😔。
怎么办呢?
我们可以在迭代中保存 pre,就能解决没有 pre 属性这个问题。另外,第一个节点是没有 pre 的,因此我们需要虚拟一个 null 就行,因为第一个节点反转之后,他的 next 一定是 null。
代码如下:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode current = head;
ListNode newHead = head;
while(current != null) {
ListNode next = current.next;
if(next == null) {
newHead = current;
}
current.next = pre;
pre = current;
current = next;
}
return newHead;
}
}
代码中,我们定义了一个 pre 节点,为了有返回值,我们也定义了一个 newHead 对象,当循环到最后时,最后一个节点就是 新的 head,所以称之为 newHead。
每次遍历时,都先保存当前节点的 next 节点,防止指针在后面错乱。然后,将 pre 节点指向当前节点的 next,然后再讲当前节点变成 pre 节点,供下次循环使用,最后,再将 next 节点变成 current 节点,供下次循环。
迭代反转就是这么简单。他的时间复杂度是 On,空间复杂度是 O1。
当然,还有一种递归方式(空间和时间复杂度都不如循环,纯粹为了炫技),后面会单独搞个文章来讲。