递归常用写法(cpp实现)

本文讨论递归的用法,不对递归的退出条件进行讨论。         

递归是对一个表两次遍历的过程。

第一次遍历是从前往后遍历,也就是未达到返回条件时一步步向下递归的过程。

第二次遍历是从后往前,也就是达到返回条件后一步步向上返回的过程。

以单链表为一个例子,结合另外几个例子来说明。链表定义如下:

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;
}

感谢阅读,觉得讲的不错请点赞支持。

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值