1.前言
对初学递归的人来说,递归无疑是很不好理解的,本系列旨在对常见算法中使用的递归做一定程度的解析,学习这些算法的同时,总结出其递归模型。以便于加深对递归的理解,同时,当我们掌握了多种递归模型。那无论何时需要使用递归解决问题,我们都能从已有的递归模型中得到一些启发。或者相似的场景使用的模型是一样时(类似于数学或物理中的建模,通过对具有某类特征的事物的分析,总结出其一般规律,以便应用到具有相同特征的情况中去),我们便能套用已有的模型使用,相信会很方便。
2.反转链表
1.问题描述
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
2.代码解析
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (head == nullptr || head->next == nullptr) { //递归出口
return head;
}
ListNode *newHead = reverseList(head->next); //保存逆转后的头节点
head->next->next = head; //反转链表
head->next = nullptr;
return newHead;
}
};
3.递归模型解析
这是一类经典的链表递归模型,即通过递归深度地遍历链表节点,最后到达递归出口,递归回升,再逆序的遍历一遍链表。在某些情况下很适用。我们知道链表是不支持随机访问的,只能通过每个节点依次遍历下去,而且单链表只能往后遍历,对于某些需要从链表尾部到头部的问题,该递归模型似乎很合适。
2.回文链表
1.问题描述
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
2.代码解析
class Solution {
public:
ListNode* frontPointer; //用于从前往后遍历的指针
bool recursivelyCheck(ListNode* head){
if(!head){
return true;
}
if(recursivelyCheck(head->next)){ //递归,逆序遍历
if(head->val==frontPointer->val){ //判断前后字符是否一致
frontPointer=frontPointer->next; //前指针指向下一个节点
return true;
}
else{
return false;
}
}
else{
return false;
}
}
bool isPalindrome(ListNode* head) {
frontPointer = head;
return recursivelyCheck(head);
}
};
3.递归模型解析
其实这类模型是反转链表的变式,它依旧利用的是递归回升逆序遍历链表的特性,只不过它是两路进行的,即递归的逆序遍历与外部变量的正向遍历。这题算是一个经典的例子。这类模型的给我们的启发是,当问题需要链表正向逆向同时进行时我们可以在递归的基础上使用一个外部变量进行正向的遍历,以此来达到两路遍历的目的。