图片.png

思路:要做到反转链表,其实要做的就是将节点的 next 从指向后一个节点改为指向前一个节点。

方法一:迭代

  1. /**
  2. * Definition for singly-linked list.
  3. * class ListNode {
  4. * val: number
  5. * next: ListNode | null
  6. * constructor(val?: number, next?: ListNode | null) {
  7. * this.val = (val===undefined ? 0 : val)
  8. * this.next = (next===undefined ? null : next)
  9. * }
  10. * }
  11. */
  12. function reverseList(head: ListNode | null): ListNode | null {
  13. // 将节点的 next 从指向后一个节点改为指向前一个节点
  14. let prev: ListNode | null = null
  15. let current: ListNode | null = head
  16. while(current) {
  17. // 使用一个变量保存当前节点的下一个节点
  18. const tmp = current.next
  19. // 将当前节点的 next 指向前一个节点
  20. current.next = prev
  21. prev = current
  22. current = tmp
  23. }
  24. return prev
  25. }

复杂度分析:

  • 时间复杂度:206. 反转链表 - 图2
  • 空间复杂度:206. 反转链表 - 图3

方法二:递归

递归的思想就是将一个过程拆分成一个个更小的过程。

假设链表没有节点或者只有一个节点,那么就应该直接返回传入的 head

  1. function reverseList(head: ListNode | null): ListNode | null {
  2. // 链表没有元素或者只有一个元素的情况
  3. if (head === null || head.next === null) {
  4. return head;
  5. }
  6. }

接下来我们假设链表只有两个节点,那么在前面的处理基础之上,它应该加上第二个节点的 next 指向第一个节点,而第一个节点的 next 指向 null 的操作,并且返回链表最后一个节点:

  1. function reverseList(head: ListNode | null): ListNode | null {
  2. if (head === null || head.next === null) {
  3. return head;
  4. }
  5. // 当链表只有两个元素的情况
  6. // 将第二个节点的 next 指向第一个节点
  7. head.next.next = head;
  8. // 将第一个节点的 next 指向 null
  9. head.next = null;
  10. return head.next.next
  11. }

当链表有两个以上的节点的时候,函数的返回值应返回最后一个节点,而最后一个节点可以通过递归得到。当上面的处理过程再加上通过递归得到最后一个节点,就是本道题目的递归方法题解:

  1. /**
  2. * Definition for singly-linked list.
  3. * class ListNode {
  4. * val: number
  5. * next: ListNode | null
  6. * constructor(val?: number, next?: ListNode | null) {
  7. * this.val = (val===undefined ? 0 : val)
  8. * this.next = (next===undefined ? null : next)
  9. * }
  10. * }
  11. */
  12. function reverseList(head: ListNode | null): ListNode | null {
  13. // 当为空链表,或者链表只有一个的时候,直接返回 head
  14. if (head === null || head.next === null) {
  15. return head
  16. }
  17. const p = reverseList(head.next)
  18. head.next.next = head;
  19. head.next = null;
  20. return p
  21. }

上面的递归操作,放在操作当前链表节点操作之前,所以设置当前节点后一个节点的 next 以及当前节点的 next 是从链表的最后一个节点开始的。

假设链表为 1 -> 2 -> 3 -> 4 -> 5,会有一下过程:

  1. 当前操作节点为 5 时,函数返回 5 这个节点的引用。
  2. 当前操作节点为 4 时,节点 5 的 next 设置为 4 的引用,而 4 的 next 设置为 null,并返回 5 节点的引用。
  3. 当前操作节点为 3 时,节点 4 的 next 设置为 3 的引用,而 3 的 next 设置为 null,并返回 5 节点的引用。
  4. 当前操作节点为 2 时,节点 2 的 next 设置为 3 的引用,而 2 的 next 设置为 null,并返回 5 节点的引用。
  5. 当前操作节点为 1 时,节点 1 的 next 设置为 2 的引用,而 1 的 next 设置为 null,并返回 5 节点的引用。

复杂度分析:

  • 时间复杂度:206. 反转链表 - 图4
  • 空间复杂度:206. 反转链表 - 图5