解题思路可以有两种方法:递归 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;
}
};