本文讨论递归的用法,不对递归的退出条件进行讨论。
递归是对一个表两次遍历的过程。
第一次遍历是从前往后遍历,也就是未达到返回条件时一步步向下递归的过程。
第二次遍历是从后往前,也就是达到返回条件后一步步向上返回的过程。
以单链表为一个例子,结合另外几个例子来说明。链表定义如下:
struct ListNode {
int val;
ListNode* next = nullptr;
}
1.从前往后
以下是最简单的从前往后的递归。
void Cur(ListNode* node) {
if (!Cur) return;
Cur(node->next);
}
我们可以添加一个代码块,使得正向遍历的进行伴随一些操作。
int temp = 0;
void Cur(ListNode* node) {
if (!node)
return;
/* code here */
/* 可以在这里操作 */
temp++;
Cur(node->next);
}
在递归的前面添加了一些代码,使得随着递归的正向进行,进行一些操作。
2.从后往前
从后往前的意思不是直接从后面开始递归,而是递归到底部往上一步步返回的过程叫从后往前。
int temp = 0;
void Cur(ListNode* node) {
if (!node)
return;
Cur(node->next);
/* code here */
/* 可以在这里操作 */
temp++;
}
如图,正向的递归没有额外的代码,而递归到栈底返回的时候,有代码,相当于反向遍历了表。
1 & 2两种遍历加起来相当于遍历了两次表。
利用这一点,既可以只在递归前的部分添加代码,实现正向遍历,也可以在递归后的部分添加代码,实现逆向遍历,还可以同时在两个部分添加代码,实现分别两次遍历并执行对应操作。
3.返回值
递归的返回值不等于函数的返回值。
递归的返回值是利用每次递归的深度的增减实现的。既可以利用函数的返回值,也可以利用传递引用参数的方法返回递归的结果。
递归返回值可以看成是深度相关的变量。
以下演示最简单的两种。
求链表深度
方法1:
int depth(ListNode* node) {
if (!node)
return 0;
return depth(node->next) + 1;
}
方法2:
int res = 0;
void depth(ListNode* node, int& res) {
if (!node) return;
depth(node->next, res++);
}
void depth(ListNode* node) {
if (!node) return;
res++;
depth(node->next);
}
void depth(ListNode* node) {
if (!node) return;
depth(node->next);
res++;
}
利用1 & 2的特点,我们可以在递归前后对外部变量操作,修改外部变量的值,也认为是递归的返回值,因此不要拘泥于递归的返回值,可以直接修改外部变量以达到目的。
4.具体例子
以力扣234题 回文链表为例子,帮助读者理解这篇文章。
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
思路:
想到时间为n,空间为1
肯定是首尾各一个指针,首指针往后移动,尾指针向前移动,直到两个指针相遇或者前面指针超过了后面的指针。
解题方法:
那么得到首指针当然很简单,难度在获取后指针,并让他往前。
我们自然想到递归,递归到底层返回的过程中,实际上就是从后往前遍历,利用这一点,我们在调用递归函数后让首指针往前走并判断即可。
#include <iostream>
using namespace std;
#include <vector>
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
class Solution {
private:
int depth = 0;
ListNode* node = nullptr;
bool ans = true;
void Cur(ListNode* head) {
if (!head)
return;
Cur(head->next);
node = node->next;
if (head->next == node || head == node)
return;
if (node->val != head->val) {
ans = false;
}
}
public:
bool isPalindrome(ListNode* head) {
node = new ListNode();
node->next = head;
Cur(head);
return ans;
}
};
ListNode* create(vector<int> const & v) {
ListNode* res = nullptr;
ListNode* node = nullptr;
for (auto x : v) {
if (!node) {
node = new ListNode(x);
res = node;
}
else {
node->next = new ListNode(x);
node = node->next;
}
}
return res;
}
int main() {
auto node = create({ 1,2 });
Solution s;
cout << s.isPalindrome(node);
return 0;
}
感谢阅读,觉得讲的不错请点赞支持。