二刷,一开始居然懵了我的天,看了一眼书上说用三个指针工具,于是实现了一下
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
if(pHead == nullptr) return nullptr;
ListNode* pNode = pHead;
ListNode* pPre = nullptr;
ListNode* pNext = pNode->next;
while(pNext != nullptr) {
pPre = pNode;
pNode = pNext;
pNext = pNext->next;
pNode->next = pPre;
}
pHead->next = nullptr;
return pNode;
}
};
代码倒是比第一次写的简洁,也挺严谨的一次过。
然后就想写递归,居然还没思路!惭愧,都有印象自己是写过的。看了一眼自己之前的代码,又实现了一下:
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
if(pHead == nullptr) return nullptr;
ListNode* pRemain = pHead->next;
pHead->next = nullptr;
return ReverseListCore(pHead, pRemain);
}
ListNode* ReverseListCore(ListNode* pReversed, ListNode* pRemain) {
if(pRemain == nullptr) return pReversed;
ListNode* pNewRemain = pRemain->next;
pRemain->next = pReversed;
return ReverseListCore(pRemain, pNewRemain);
}
};
这里要尽量再把递归总结总结。递归真强:
1.和父函数的参数可以不一样:利用这点,可以携带更多信息,使问题更有针对性。
2.不一定是大问题调用小问题,这道题就很有意思,是每调用一次往后走一步。总之每步使问题有进展就好。
3.返回值:可以没有返回值,也可以返回子函数的返回值,和子函数的返回值类型结合使用。
4.终止条件想清楚。看似风轻云淡实则非常重要。
递归和循环总是有异曲同工之妙,也许这个递归子函数有两个参数的思路的灵感来源于需要三个工具指针吧。
时间过得好快,加油!