解题思路可以有两种方法:递归 or 迭代。
\qquad 迭代:通过使用for
循环遍历,完成目标。方法直观,容易理解。
\qquad 递归:通过函数调用其自身,完成目标。递归最复杂、最重要的部分就是递归函数的构建,构建递归函数可以从以下几方面考虑:
\qquad\qquad 1)函数的终止条件的设立。
\qquad\qquad 2)目标拆解后,函数每一步需要重复执行的操作。
\qquad\qquad 3)不同递归层级间的信息传递,可借助参数、返回值、外部变量等。
递归思路:
\qquad 一开始的思路,从刚才上面三个角度分析:
\qquad 1)当前head
为最后一个节点时,返回head
,作为翻转后链表的表头。
\qquad 2)每一步重复将当前head
添加到新链表的末尾。
\qquad 3)观察可发现,完成每一步的操作需要两个信息:
\qquad\qquad 1 - 翻转后链表的表头,用于题目输出,只能作为递归函数的返回值传递。
\qquad\qquad 2 - 翻转后链表的末尾,用于重复将当前节点添加到链表末尾,被函数各层调用使用,一开始的思路是,是用全局变量去存储链表末尾,并在每次操作后不断更新。
优化思路:
\qquad 思路大致相同,但是能否优化无需使用全局变量来存储链表末尾?
\qquad 可以利用链表本身的特性,找到链表的末尾,如下所示:
\qquad\qquad 1 → \rightarrow → 2 → \rightarrow → 3 → \rightarrow → 4 → \rightarrow → 5 \qquad (原本的链表)
\qquad\qquad 1 → \rightarrow → 2 → \rightarrow → 3 ← \leftarrow ← 4 ← \leftarrow ← 5 \qquad (部分反转的链表)
\qquad 现在,函数递归到节点2,如何找到翻转链表的末尾?从图中可以很直观的理解:
\qquad end node = 2 -> next
, 只需要将 2 -> next -> next = node 2
,便可以将2翻转:
\qquad\qquad 1 → \rightarrow → 2 ← \leftarrow ← 3 ← \leftarrow ← 4 ← \leftarrow ← 5 \qquad
\qquad 另外需要注意的点,由于每次操作是重复的,如果仅仅改变指针的指向会导致反转后的链表未能指向nullptr
,因此在每一步操作中,需额外将反转链表末尾指向nullptr
。
class Solution {
public:ListNode* reverseList(ListNode* head) {if(head == nullptr || head->next == nullptr){return head;}ListNode* revhead = reverseList(head->next);head->next->next = head;head->next = nullptr;return revhead;}
};