递归的理解---1

开门见山:

不要试图在脑中复现递归函数的调用栈,你只要相信递归函数的作用即可。

重点提示:

1.不要试图在脑中复现递归函数的调用栈,你只要相信递归函数的作用即可。重要的事情多说一遍,否则你容易陷入一种脑循环(你的小脑袋瓜嗡嗡的也循环不出来),如果是单层的递归调用你可能还好理解,但是如果是函数多次调用自己进行递归,你会发现跟着开发工具步步跟调,也很难去理解中间这个调用过程,且调用次数稍多,就涉及到大量的步骤,我们只要相信算法本身,相信上一步会给我们返回准确的结果,相信它的作用即可。
2.一定要理解递归的真切含义,是先递过去再从后面依次送过来,就像别的文章中经常举的一个例子,一个长长的队伍,你在队伍中间,想知道你是第几个,你拍前一个人的肩膀,前面的人也不知道,继续问前面的,直到问道第一个人,第一个人扭头告诉第二个人,然后从第二个人依次向后位置依次加1,直到最后再走回你这里,你知道了你的位置。

具体讲解:

第一、 明确递归函数的作用和参数的含义,然后坚定的相信它的作用


再次强调不要试图在脑中重演递归过程,当然你也做不到。你要做的便是:明确递归函数的作用,包括参数是什么,是否有返回值,有的话返回值是什么,然后相信它就行了。

第二、找到递归基


所谓递归基,就是递归结束的条件。比如 n == 0的时候之类的情况。

第三、明确递归函数返回后,该做点啥


里层的递归函数返回后,需要与当前的层做一些互动,然后才能将彼此联系起来。

思考技巧
就是将问题拆分成两个部分, 即1剩余整体,其中剩余整体又可以用1剩余整体的思想来考虑.如此思考,那么剩余整体完全可以用递归的方法去解决.
重中之重的点如下联系到第一点技巧的提示,即_相信剩余整体已经处理完毕_之后如何与_1的部分_衔接问题.

现在这么一说可能会很抽象,在例子中会给出很形象的解释.


示例分析

求和

使用for循环很容易求和1+2+3+...+n, 那么使用递归的方法呢?

  • 定义求和函数sum.明确函数作用, 给定一个n,sum(n)返回1+2+...+n的总和
  • 找到递归基, 当n=1时,返回1
  • 利用1剩余整体的思想找到递推式.1+2+...+n可以分解成1+2+...+n-1n的和,其中最后的n即可代表1的思想,1+2+...+n-1代表剩余整体的思想.相信sum函数的作用,即sum(n-1)返回1+2+...+n-1的结果.总结一下即为nsum(n-1)的问题.

代码如下

    public static int sum(int n){
        if (n == 1){
            return 1;
        }
        return n + sum(n - 1);
    }
    sum(10)
    # 55

当我们写 return n + sum(n-1) 要想到关于递归的第一个技巧,我们假设sum(n-1)是没有问题的,正常返回1+2+...+n-1的和,不要自己绕进去.递归求和就是这么简单.

数组内部的最大值


用循环的方法,同样是很简单的.那么递归呢

假设有数组

l = [23, 34, 2, 4, 56, 23, 1, 56, 78]
  • 定义一个求数组最大值的函数max.明确其作用,给定一个数组,返回其中的最大值
  • 找到递归基,即当数组的元素为1时,返回这个数组元素即可
  • 利用1整体思想去寻找递归关系式.将数组第一项的23作为1, 将剩下的[34, 2, 4, 56, 23, 1, 56, 78]作为一个整体.则 比较 23max([34, 2, 4, 56, 23, 1, 56, 78])两者的大小,如果前者大,返回23,否则返回后者.

代码如下

public class Recursion {
    public static void main(String[] args) {
        int[] arr = {1, 5, 3, 9, 13, 7, 25, 19, 37, 123, 16, 255, 1234, 125, 1379, 233, 345, 235, 7890, 11111};
        int maxNumber = MaxNumber(arr, 0, arr.length - 1);
        System.out.println("maxNumber = " + maxNumber);
    }

    public static int MaxNumber(int[] arr, int low, int high) {
        //随着递归的进行,数组的边界会改变.
        //直接定义在接口处,递归更容易实现和理解.因为这样一来,容易切割实现1和剩余整体的思想.
        if (low == high) {
            //递归基,此时数组中只有一个元素,返回即可
            return arr[low];
        }
        int left = arr[low];//1的思想
        int right = MaxNumber(arr, low + 1, high);//剩余整体的思想
        return Math.max(left, right);
    }
}

单向链表的翻转

牛客网题

输入一个链表,反转链表后,输出新链表的表头

假设有一个链表

1->2->3->4->5->NULL
  • 定义一个函数ReverseList, 翻转一个链表.返回新链表的头结点
  • 找到递归基,如果一个链表只有一个节点,那么直接返回即可.
  • 利用1和剩余整体的思想去解决此问题.

我们将原始链表的头结点1作为1,将2->3->4->5->NULL作为剩余整体.即第一个节点与ReverseList(2->3->4->5->NULL)如何链接的问题.

我们相信ReverseList函数作用,即ReverseList(2->3->4->5->NULL)已经被翻转成功,而且返回新链表的头结点.

我们如何连接这两个部分呢?

代码如下

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/

// 递归算法
class Solution {
public:
    ListNode* ReverseList(ListNode* head) {
        // 递归基
        if (head == NULL || head->next == NULL) return head;
        // 当前节点的下一节点
        ListNode* next_node = head->next;
        ListNode* new_head = ReverseList(next_node);
        next_node->next = head;  # 下面这两句是建立两部分的连接
        head->next = NULL;       # 当前节点的下一节点需要保存一下
        return new_head;
    }
};


// 迭代算法
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        if (!pHead || !pHead->next) {
            return pHead;
        }
        ListNode* pPre = NULL;
        ListNode* pNode = pHead;
        ListNode* pNext = NULL;
        while (pNode) {
            pNext = pNode->next;
            pNode->next = pPre;
            pPre = pNode;
            pNode = pNext;
        }
        return pPre;
    }
};

二叉树的最大深度

nowcoder

输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度.

class Solution {
public:
    // step1: 定义TreeDepth函数,它的作用是找到并且返回给定树节点对应的树的最大深度
    int TreeDepth(TreeNode* pRoot)
    {
        // 找到递归基
        if (pRoot == NULL) return 0;
        // 递归关系式 Depth(root) Depth(root->left) Depth(root->right)
        int left = TreeDepth(pRoot->left);
        int right = TreeDepth(pRoot->right);
        // 根据递归关系式与返回值,决定最终返回 1+max(left, right)
        return 1 + max(left, right);
    }
};

例子未完待续...

posted @ 2020-12-28 10:10  皮卡丘和羊宝贝😄  阅读(100)  评论(0编辑  收藏  举报